Dan WilsonPersonal website of Dan Wilson2024-02-28T00:00:00Zhttps://danielcwilson.com/Dan WilsonThe New CSS Math: pi and other constants2024-02-28T00:00:00Zhttps://danielcwilson.com/posts/mathematicss-constants/<p class="preamble">
CSS added many new Math constants to be used inside Math functions (such as <code>calc()</code>). The new constants are <code>pi</code>, <code>e</code>, <code>infinity</code>, <code>-infinity</code>, and <code>NaN</code>. <b>As of February 2024, these CSS constants are available in the latest Edge, Chrome, Safari and Firefox browsers.</b>
</p>
<h3 id="the-basics-of-css-pi" tabindex="-1">The basics of CSS <code>pi</code> <a class="direct-link" href="https://danielcwilson.com/posts/mathematicss-constants/#the-basics-of-css-pi" aria-hidden="true">#</a></h3>
<p>When used inside a Math function (<code>calc()</code>, <code>pow()</code>, <code>round()</code>, etc.), <code>pi</code> equates to the mathematical constant value pi (π, approximately 3.142). Just as we are able to in JavaScript via <code>Math.pi</code> we can use the constant directly instead of using an approximated value.</p>
<pre class="language-css"><code class="language-css"><span class="token property">width</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>pi * 3px<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* ~9.42px */</span><br /><span class="token property">width</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>pi * 1rad<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* ~3.14rad = 180deg */</span><br /><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>pi * .5<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* ~1.57 */</span></code></pre>
<p>It’s important to note that none of these mathematical constants can be used outside of a math function. When used without a math function they will be a generic string. That could still result in valid CSS (such as an animation named <code>pi</code> used with <code>animation-name: pi</code>), but more than likely it will be invalid if you are trying to use it as a number. If you want it to equate to the number pi, you’ll need it inside a math function.</p>
<pre class="language-css"><code class="language-css"><span class="token property">line-height</span><span class="token punctuation">:</span> pi<span class="token punctuation">;</span> <span class="token comment">/* invalid */</span><br /><span class="token property">animation-name</span><span class="token punctuation">:</span> pi<span class="token punctuation">;</span> <span class="token comment">/* valid as string, will use keyframes defined as pi */</span><br /><span class="token property">animation-iteration-count</span><span class="token punctuation">:</span> pi<span class="token punctuation">;</span> <span class="token comment">/* invalid */</span><br /><span class="token property">animation-iteration-count</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>pi<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* valid, ~3.14 */</span><br /><span class="token property">animation-iteration-count</span><span class="token punctuation">:</span> <span class="token function">round</span><span class="token punctuation">(</span>pi<span class="token punctuation">,</span> 1<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* valid, 3 */</span><br /><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">pow</span><span class="token punctuation">(</span>pi<span class="token punctuation">,</span> 2<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* valid, ~9.87 */</span></code></pre>
<h4 id="some-use-cases-with-pi" tabindex="-1">Some use cases with <code>pi</code> <a class="direct-link" href="https://danielcwilson.com/posts/mathematicss-constants/#some-use-cases-with-pi" aria-hidden="true">#</a></h4>
<p>The benefits of using <code>pi</code> appear to be more about clarity of intention than specific mathematical precision. When used in combination with pixels, I would expect pi to represent approximately 3.1415927px. Using <code>getComputedStyle()</code> in the latest versions of Firefox, Safari, and Chrome (February 2024) gave <a href="https://codepen.io/danwilson/pen/YzgmXrv">mildly different calculations</a> when used.</p>
<div class="table-wrap">
<table>
<thead>
<tr>
<th>Specified calc()</th>
<th>Firefox</th>
<th>Safari</th>
<th>Chrome</th>
</tr>
</thead>
<tbody>
<tr>
<th>pi * 1px</th>
<td>3.13333px</td>
<td>3.140625px</td>
<td>3.14062px</td>
</tr>
<tr>
<th>pi * 10px</th>
<td>31.4167px</td>
<td>31.40625px</td>
<td>31.4062px</td>
</tr>
<tr>
<th>pi * 100px</th>
<td>314.167px</td>
<td>314.15625px</td>
<td>314.156px</td>
</tr>
<tr>
<th>pi * 100000px</th>
<td>314159px</td>
<td>314159.25px</td>
<td>314159px</td>
</tr>
</tbody>
</table>
</div>
<p>If you are familiar with using radians in defining angles in mathematical contexts, the introduction of the <code>pi</code> constant brings more clarity to CSS. Previously, I never found myself reaching for radians when specifying angles in CSS, because they are based around pi. One complete rotation is <code>2 * pi radians</code>, and previously we had to specify that in CSS as <code>6.284rad</code> or a similar approximation. Radians are not always intuitive when you have to specify values in only a decimal number.</p>
<p>The following are all equivalent ways to define halfway around for a rotation.</p>
<pre class="language-css"><code class="language-css"><span class="token property">rotate</span><span class="token punctuation">:</span> 180deg<span class="token punctuation">;</span><br /><span class="token property">rotate</span><span class="token punctuation">:</span> .5turn<span class="token punctuation">;</span><br /><span class="token property">rotate</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>pi * 1rad<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token property">rotate</span><span class="token punctuation">:</span> 3.142rad<span class="token punctuation">;</span></code></pre>
<p>We can also use <code>pi</code> to simplify calculating lengths of circles and curves. The total length of a circle’s stroke can be calculated in CSS directly since the circumference of a circle is defined as <code>2 * pi * radius</code>, so we can use the raw length for a <a href="https://css-tricks.com/svg-line-animation-works/">stroke dash animation</a>.</p>
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="bGZPmbz" data-user="danwilson" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/bGZPmbz">
DashOffset animation with CSS pi</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<h3 id="the-basics-of-css-infinity" tabindex="-1">The basics of CSS <code>infinity</code> <a class="direct-link" href="https://danielcwilson.com/posts/mathematicss-constants/#the-basics-of-css-infinity" aria-hidden="true">#</a></h3>
<p>There are two usable constants to represent Infinity which are <code>infinity</code> and its opposite of <code>-infinity</code>. Both effectively represent the largest possible value, as a positive or negative, respectively.</p>
<pre class="language-css"><code class="language-css"><span class="token property">z-index</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>infinity<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token property">z-index</span><span class="token punctuation">:</span> <span class="token function">pow</span><span class="token punctuation">(</span>infinity<span class="token punctuation">,</span> 1<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token property">left</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>-infinity * 1px<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token property">opacity</span><span class="token punctuation">:</span> <span class="token function">round</span><span class="token punctuation">(</span>down<span class="token punctuation">,</span> infinity<span class="token punctuation">,</span> infinity<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* weird, but valid */</span></code></pre>
<p>Again, one of the biggest benefits of using <code>infinity</code> is clarity of intent. If you are trying to say you want the highest possible pixel value to ensure it is pushed off screen, <code>infinity</code> might be a clearer (and safer) choice than specifying an arbitrary value you assume is the largest reasonable value.</p>
<p>Depending on the browser and the type calculated, <code>infinity</code> can compute to fairly different values, but still consistently large. For further reading, Will Boyd discusses some interesting <a href="https://codersblock.com/blog/playing-with-infinity-in-css/">uses cases and computed value fun</a> for <code>infinity</code>.</p>
<h3 id="the-basics-of-css-e" tabindex="-1">The basics of CSS <code>e</code> <a class="direct-link" href="https://danielcwilson.com/posts/mathematicss-constants/#the-basics-of-css-e" aria-hidden="true">#</a></h3>
<p>To represent the <a href="https://mathworld.wolfram.com/e.html">mathematical constant for Euler’s number</a>, we now have... <code>e</code>! This constant is used with logarithms and exponential growth in mathematics, and it equates to approximately 2.71828.</p>
<p>The same rule applies here as for the other constants: it must be used in a function like <code>calc()</code>.</p>
<pre class="language-css"><code class="language-css"><span class="token property">opacity</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>e / 3<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* ~.906 */</span><br /><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">pow</span><span class="token punctuation">(</span>e<span class="token punctuation">,</span> 2<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* ~7.389; */</span><br /><span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>e * 1rem<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* ~2.71828rem */</span><br /><span class="token property">opacity</span><span class="token punctuation">:</span> e<span class="token punctuation">;</span> <span class="token comment">/* invalid */</span></code></pre>
<h3 id="the-basics-of-css-nan" tabindex="-1">The basics of CSS <code>NaN</code> <a class="direct-link" href="https://danielcwilson.com/posts/mathematicss-constants/#the-basics-of-css-nan" aria-hidden="true">#</a></h3>
<p>The last numeric constant added to CSS is <code>NaN</code>, everyone’s favorite not-a-number representation. As with most of these Math additions to CSS, they allow for correlation to the existing JavaScript Math concepts, and <code>NaN</code> is no different. Spec-wise, it allows a representation for values that do not exist for certain function usage. For example, finding a remainder with a zero (such as <code>rem(3, 0)</code>) will result in <code>NaN</code> because dividing by zero is not mathematically possible. Offering this in the spec gives a way to both map to the JavaScript version of <code>NaN</code> and represent situations where a CSS calculation does not result in a number in a clear cut manner.</p>
<p>In practice, however, CSS has to resolve to some value. If you try to find the computed value of scenarios with <code>NaN</code>, used either as a direct value or in a calculation that resolves to it, you will find a valid value ultimately applied.</p>
<p>For example for an element with the following specific CSS</p>
<pre class="language-css"><code class="language-css"><span class="token selector">#element</span> <span class="token punctuation">{</span><br /> <span class="token property">opacity</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span><br /> <span class="token property">opacity</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>NaN<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>In each of Firefox, Safari, and Chrome, the second opacity declaration gets applied as <a href="https://codepen.io/danwilson/pen/zYXOogw??editors=1111">it is a valid value</a>. In this case, the computed value applied is <code>0</code>. Similarly, if the second opacity had been defined as <code>opacity: rem(9, 0)</code> (which the spec says should resolve to <code>NaN</code> whenever the second parameter is zero) the computed value is still <code>0</code> since <code>rem(9, 0)</code> and <code>calc(NaN)</code> are both effectively the same <code>NaN</code>.</p>
<p>Attempting <code>width: calc(NaN * 1px)</code> results in a computed value of <code>0px</code>. A <code>z-index: calc(NaN)</code> is also <code>0</code>... as is <code>z-index: calc(NaN * infinity)</code>.</p>
<p>But now you’re just asking for trouble.</p>
The New CSS Math: pow(), sqrt(), and exponential friends2024-02-13T00:00:00Zhttps://danielcwilson.com/posts/mathematicss-powers/<p class="preamble">
CSS added many new Math functions to supplement the old favorites (such as <code>calc()</code>). They all ultimately represent a numeric value, but the nuance in how they work is not always clear from the start. <b>As of February 2024, these CSS functions are available in the latest Edge, Chrome, Safari and Firefox browsers.</b>
</p>
<h3 id="the-basics-of-css-pow()" tabindex="-1">The basics of CSS <code>pow()</code> <a class="direct-link" href="https://danielcwilson.com/posts/mathematicss-powers/#the-basics-of-css-pow()" aria-hidden="true">#</a></h3>
<p>Powers in math allow us to specify how many times to multiply a number by itself.</p>
<p>Now available in CSS, the <code>pow()</code> function takes two parameters: our initial number and the exponent value to apply to it.</p>
<pre class="language-css"><code class="language-css"><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">pow</span><span class="token punctuation">(</span>3<span class="token punctuation">,</span> 2<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 9 */</span><br /><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">pow</span><span class="token punctuation">(</span>3<span class="token punctuation">,</span> 3<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 27 */</span><br /><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">pow</span><span class="token punctuation">(</span>2<span class="token punctuation">,</span> 4<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 16 */</span></code></pre>
<p>This mirrors the functionality long available in JavaScript via <code>Math.pow()</code>.</p>
<pre class="language-js"><code class="language-js">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">pow</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 3 * 3 = 9</span><br />console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">pow</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 3 * 3 * 3 = 27</span><br />console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">pow</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 2 * 2 * 2 * 2 = 16</span></code></pre>
<p>Unlike many of the other new CSS Math Functions, <code>pow()</code> only works with raw numbers. You cannot apply units inside the function, so in order to get a unit you will need to use <code>pow()</code> in combination with <code>calc()</code>,</p>
<pre class="language-css"><code class="language-css"><span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>1rem * <span class="token function">pow</span><span class="token punctuation">(</span>2<span class="token punctuation">,</span> 2<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 1rem * 4 = 4rem */</span><br /><span class="token property">rotate</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>5deg * <span class="token function">pow</span><span class="token punctuation">(</span>2<span class="token punctuation">,</span> 5<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 5deg * 32 = 160deg */</span></code></pre>
<h3 id="but-what-about-the-roots" tabindex="-1">But what about the roots? <a class="direct-link" href="https://danielcwilson.com/posts/mathematicss-powers/#but-what-about-the-roots" aria-hidden="true">#</a></h3>
<p>Just like we have <code>Math.sqrt()</code> in JavaScript, we now have <code>sqrt()</code> in CSS to find the square root of a number. It takes one parameter, and like <code>pow()</code> it works with just numbers (not lengths, percentages, and other types that have units)</p>
<pre class="language-css"><code class="language-css"><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">sqrt</span><span class="token punctuation">(</span>4<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 2 */</span><br /><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">sqrt</span><span class="token punctuation">(</span>9<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 3 */</span><br /><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">sqrt</span><span class="token punctuation">(</span>12<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* about 3.4641 */</span></code></pre>
<p>If you want to take a root that is not square (such as cube root, etc.), you will still need to use <code>pow()</code>. If you use a fraction as your exponent, you get a root (such as <code>1/3</code> for a cube root).</p>
<pre class="language-css"><code class="language-css"><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">pow</span><span class="token punctuation">(</span>4<span class="token punctuation">,</span> .5<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* square root of 4: 2 */</span><br /><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">pow</span><span class="token punctuation">(</span>4<span class="token punctuation">,</span> 1/2<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* square root of 4: 2 */</span><br /><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">pow</span><span class="token punctuation">(</span>27<span class="token punctuation">,</span> 1/3<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* cube root of 27: 3 */</span><br /><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">pow</span><span class="token punctuation">(</span>2<span class="token punctuation">,</span> 3/2<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* cubed and then a square root: about 2.8284 */</span></code></pre>
<h3 id="using-these-new-math-functions-in-practice" tabindex="-1">Using these new math functions in practice <a class="direct-link" href="https://danielcwilson.com/posts/mathematicss-powers/#using-these-new-math-functions-in-practice" aria-hidden="true">#</a></h3>
<p>As with many of these new math functions, how you will use them in daily work is not always clear.</p>
<p>In the spec, an example is shown to use <code>pow()</code> for <a href="https://drafts.csswg.org/css-values/#example-bebe620e">font sizes and a modular scale</a>. With this each heading, for example, can be in relation to the same root size. While use of <code>pow()</code> is not strictly needed here as values could be calculated and then pasted in, readability is helped for maintenance as the intent is clearer when showing the <code>pow()</code>.</p>
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="KKEGqGm" data-user="danwilson" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/KKEGqGm">
CSS pow() and Modular Scale</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>Or you can think a bit outside the box.</p>
<p>Combined with <code>@property</code> and Custom Properties, we can create a linear animation that feels like it has easing. That is, the animation should proceed equally over time, but by using exponents our animation feels like it is starting slow and then speeding up.</p>
<p>We can animate a variable from 1 to 10 with a linear timing function. Then we apply that variable as the exponent of a <code>pow()</code> for some transform (like a rotation or translation). The animation will be from 1 to 10 evenly but the value of the transform will increase exponentially, speeding up the resulting visual motion.</p>
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="xxByrmy" data-user="danwilson" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/xxByrmy">
exponential animation easing</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<h3 id="other-exponential-functions" tabindex="-1">Other exponential functions <a class="direct-link" href="https://danielcwilson.com/posts/mathematicss-powers/#other-exponential-functions" aria-hidden="true">#</a></h3>
<p>There are three other functions related to exponents to know about.</p>
<h4 id="e-to-a-power-with-exp()" tabindex="-1"><code>e</code> to a power with <code>exp()</code> <a class="direct-link" href="https://danielcwilson.com/posts/mathematicss-powers/#e-to-a-power-with-exp()" aria-hidden="true">#</a></h4>
<p>The <code>exp()</code> function takes one parameter, representing the exponent to apply to the <a href="https://mathworld.wolfram.com/e.html">mathematical constant <code>e</code></a>. So <code>exp(3)</code> is equivalent to <code>pow(e, 3)</code>, and like <code>pow()</code> it also does not allow units. This behaves similarly to <code>Math.exp()</code> in JavaScript.</p>
<h4 id="logarithms-with-log()" tabindex="-1">Logarithms with <code>log()</code> <a class="direct-link" href="https://danielcwilson.com/posts/mathematicss-powers/#logarithms-with-log()" aria-hidden="true">#</a></h4>
<p>Relatedly, <code>log()</code> takes two parameters (the second is optional) and represents <a href="https://mathworld.wolfram.com/Logarithm.html">logarithms</a>.</p>
<p>In JavaScript <code>Math.log</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log">only takes one parameter</a>, and it represents the natural logarithm of the number passed as the parameter. The base of this logarithm is <code>e</code>.</p>
<p>The optional second parameter that CSS adds for <code>log()</code> allows us to change the base from <code>e</code> to a new number.</p>
<pre class="language-css"><code class="language-css"><span class="token property">opacity</span><span class="token punctuation">:</span> <span class="token function">log</span><span class="token punctuation">(</span>2<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* log 2 for base e = .693147 */</span><br /><span class="token property">opacity</span><span class="token punctuation">:</span> <span class="token function">log</span><span class="token punctuation">(</span>2<span class="token punctuation">,</span> 10<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* log 2 for base 10 = .30103 */</span></code></pre>
<p>JavaScript does not have a second parameter, so CSS adds the base change as a convenience. The equivalent of CSS <code>log(number, base)</code> can be achieved in JavaScript as <code>Math.log(number) / Math.log(base)</code>.</p>
<h4 id="the-square-root-of-sum-of-squares-with-hypot()" tabindex="-1">The square root of sum of squares with <code>hypot()</code> <a class="direct-link" href="https://danielcwilson.com/posts/mathematicss-powers/#the-square-root-of-sum-of-squares-with-hypot()" aria-hidden="true">#</a></h4>
<p>It’s a lot of words, but it is a fun, niche function.</p>
<p>In geometry with a right triangle, you can find the length of the hypotenuse (the side opposite the right angle) by the following process</p>
<ol>
<li>Square both the other sides</li>
<li>Add these values together</li>
<li>Square root the sum from the previous step</li>
</ol>
<p class="codepen" data-height="323" data-default-tab="result" data-slug-hash="qBvQmvm" data-user="danwilson" style="height: 323px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/qBvQmvm">
Hypotenuse on Resize</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>So with CSS the <code>hypot()</code> function (and in JavaScript with the <code>Math.hypot()</code> method), we can pass in an arbitrary amount of parameters. The function will then square all the parameters, add them together, and take the square root.</p>
<pre class="language-css"><code class="language-css"><span class="token property">animation-iteration-count</span><span class="token punctuation">:</span> <span class="token function">hypot</span><span class="token punctuation">(</span>2<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 2 */</span><br /><span class="token property">animation-iteration-count</span><span class="token punctuation">:</span> <span class="token function">hypot</span><span class="token punctuation">(</span>3<span class="token punctuation">,</span> 4<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 5 = sqrt(9 + 16) = sqrt(25) */</span><br /><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">hypot</span><span class="token punctuation">(</span>1<span class="token punctuation">,</span> 2<span class="token punctuation">,</span> 3<span class="token punctuation">,</span> 4<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* ~5.4772 = sqrt(1 + 4 + 9 + 16) = sqrt(30) */</span><br /><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">hypot</span><span class="token punctuation">(</span>-2<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 2 */</span><br /><span class="token property">width</span><span class="token punctuation">:</span> <span class="token function">hypot</span><span class="token punctuation">(</span>30px<span class="token punctuation">,</span> 40px<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 50px = sqrt(900px + 1600px) = sqrt(2500px) */</span></code></pre>
<p>This is the one function discussed in this article that <em>does allow units</em> as long as all items are of the same type.</p>
<pre class="language-css"><code class="language-css"><span class="token property">translate</span><span class="token punctuation">:</span> <span class="token function">hypot</span><span class="token punctuation">(</span>3px<span class="token punctuation">,</span> 4px<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 5px = sqrt(9px + 16px) = sqrt(25px) */</span><br /><span class="token property">translate</span><span class="token punctuation">:</span> <span class="token function">hypot</span><span class="token punctuation">(</span>3px<span class="token punctuation">,</span> .25rem<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 5px = sqrt(9px + 16px) = sqrt(25px) */</span><br /><span class="token property">rotate</span><span class="token punctuation">:</span> <span class="token function">hypot</span><span class="token punctuation">(</span>3deg<span class="token punctuation">,</span> 4deg<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 5deg = sqrt(9deg + 16deg) = sqrt(25deg) */</span></code></pre>
The New CSS Math: rem() and mod()2023-10-29T00:00:00Zhttps://danielcwilson.com/posts/mathematicss-rem-mod/<p class="preamble">
CSS added many new Math functions to supplement the old favorites (such as <code>calc()</code>). They all ultimately represent a numeric value, but the nuance in how they work is not always clear from the start. <b>As of October 2023, these are available in the latest Safari and Firefox. They are also available in Edge/Chrome behind the Experimental Web Platform feature flag.</b>
</p>
<h3 id="the-basics-of-the-css-rem()-function" tabindex="-1">The basics of the CSS <code>rem()</code> function <a class="direct-link" href="https://danielcwilson.com/posts/mathematicss-rem-mod/#the-basics-of-the-css-rem()-function" aria-hidden="true">#</a></h3>
<p>The mathematical concept of a remainder comes from division, representing what remains when a number does not divide evenly into another number. For example, with <code>9 ÷ 4</code>, <code>9</code> is not a multiple of <code>4</code>, so <code>4</code> does not divide evenly into <code>9</code>. You can add two <code>4</code>s to get <code>8</code>, but you still have a <code>1</code> left over to get to <code>9</code>, so <code>1</code> is our <em>remainder</em>.</p>
<p>In JavaScript we can do this with an operator: <code>%</code>:</p>
<pre class="language-js"><code class="language-js">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token number">9</span> <span class="token operator">%</span> <span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 1</span><br />console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token number">5</span> <span class="token operator">%</span> <span class="token number">4.1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 0.9</span><br />console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token number">1003</span> <span class="token operator">%</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 3</span></code></pre>
<p>In CSS, we now have access to the <code>rem()</code> function to calculate a remainder. It takes two parameters, as JavaScript has two numbers to use with the remainder operator <code>%</code>. In mathematical terms, the first number is the dividend and the second is the divisor.</p>
<p>The following CSS representations would be equivalent to the previous JavaScript examples:</p>
<pre class="language-css"><code class="language-css"><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">rem</span><span class="token punctuation">(</span>9<span class="token punctuation">,</span> 4<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 1 */</span><br /><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">rem</span><span class="token punctuation">(</span>5<span class="token punctuation">,</span> 4.1<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 0.9 */</span><br /><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">rem</span><span class="token punctuation">(</span>1003 % 5<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 3 */</span></code></pre>
<p>Since we are in CSS, we also have to consider units. Both parameter values need to be of the same <em>type</em>, such as a length or an angle representation.</p>
<pre class="language-css"><code class="language-css"><span class="token property">rotate</span><span class="token punctuation">:</span> <span class="token function">round</span><span class="token punctuation">(</span>20deg<span class="token punctuation">,</span> 5deg<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 0deg */</span><br /><span class="token property">rotate</span><span class="token punctuation">:</span> <span class="token function">round</span><span class="token punctuation">(</span>20deg<span class="token punctuation">,</span> 7deg<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 6deg */</span><br /><span class="token property">rotate</span><span class="token punctuation">:</span> <span class="token function">round</span><span class="token punctuation">(</span>20deg<span class="token punctuation">,</span> 3deg<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 2deg */</span></code></pre>
<p>You can mix units if they are of the same type. For example we can mix <code>deg</code> and <code>turn</code> since both of those represent angles.</p>
<pre class="language-css"><code class="language-css"><span class="token property">rotate</span><span class="token punctuation">:</span> <span class="token function">round</span><span class="token punctuation">(</span>100deg<span class="token punctuation">,</span> .25turn<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 10deg (100 % 90) */</span><br /><span class="token property">rotate</span><span class="token punctuation">:</span> <span class="token function">round</span><span class="token punctuation">(</span>200deg<span class="token punctuation">,</span> .25turn<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 20deg (200 % 90) */</span></code></pre>
<p class="codepen" data-height="450" data-default-tab="css,result" data-slug-hash="RwEwOmP" data-user="danwilson" style="height: 450px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/RwEwOmP">
CSS Math functions: rem() (Visual reference)</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>The value will always take the sign of the first parameter (dividend). So if the dividend is negative, the result will be negative. The sign of the second parameter (divisor) has no effect on the result.</p>
<pre class="language-css"><code class="language-css"><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">rem</span><span class="token punctuation">(</span>9<span class="token punctuation">,</span> 4<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 1 */</span><br /><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">rem</span><span class="token punctuation">(</span>-9<span class="token punctuation">,</span> 4<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* -1 */</span><br /><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">rem</span><span class="token punctuation">(</span>9<span class="token punctuation">,</span> -4<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 1 */</span><br /><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">rem</span><span class="token punctuation">(</span>-9<span class="token punctuation">,</span> -4<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* -1 */</span></code></pre>
<h3 id="the-basics-of-the-css-mod()-function" tabindex="-1">The basics of the CSS <code>mod()</code> function <a class="direct-link" href="https://danielcwilson.com/posts/mathematicss-rem-mod/#the-basics-of-the-css-mod()-function" aria-hidden="true">#</a></h3>
<p>Closely related to the concept of remainders is the modulus function. When both the dividend and divisor have the same sign, both functions have an equivalent result.</p>
<pre class="language-css"><code class="language-css"><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">rem</span><span class="token punctuation">(</span>9<span class="token punctuation">,</span> 4<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 1 */</span><br /><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">mod</span><span class="token punctuation">(</span>9<span class="token punctuation">,</span> 4<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 1 */</span><br /><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">rem</span><span class="token punctuation">(</span>-9<span class="token punctuation">,</span> -4<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* -1 */</span><br /><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">mod</span><span class="token punctuation">(</span>-9<span class="token punctuation">,</span> -4<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* -1 */</span></code></pre>
<p>However, where the <code>rem()</code> function takes the sign of the dividend, <code>mod()</code> takes the sign of the divisor.</p>
<pre class="language-css"><code class="language-css"><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">mod</span><span class="token punctuation">(</span>9<span class="token punctuation">,</span> 4<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 1 */</span><br /><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">mod</span><span class="token punctuation">(</span>-9<span class="token punctuation">,</span> 4<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 1 */</span><br /><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">mod</span><span class="token punctuation">(</span>9<span class="token punctuation">,</span> -4<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* -1 */</span><br /><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">mod</span><span class="token punctuation">(</span>-9<span class="token punctuation">,</span> -4<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* -1 */</span></code></pre>
<p>And most importantly... you have to think differently with <code>mod()</code> when you have a mix of signs. Let’s start with an example:</p>
<pre class="language-css"><code class="language-css"><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">rem</span><span class="token punctuation">(</span>-9<span class="token punctuation">,</span> 4<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 1 */</span><br /><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">mod</span><span class="token punctuation">(</span>-9<span class="token punctuation">,</span> 4<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* -3 */</span><br /><br /><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">rem</span><span class="token punctuation">(</span>9<span class="token punctuation">,</span> -4<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* -1 */</span><br /><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">mod</span><span class="token punctuation">(</span>9<span class="token punctuation">,</span> -4<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 3 */</span></code></pre>
<p>If you take away the signs, for remainders, we typically think how many multiple of the divsor can fit in the dividend. In the case of <code>rem(9, 4)</code> two multiples of <code>4</code> fit into <code>9</code> (because <code>2 * 4 = 8</code>), and the remainder is <code>1</code> (because <code>9 - 8 = 1</code>).</p>
<p>For <code>mod()</code> in the case where there is one negative sign and one positive sign, I think about it like I am looking for the multiple <em>bigger</em> than the dividend. So for <code>mod(9, -4)</code>, you look at the multiple just past the dividend (<code>4 * 3 = 12</code>). And as per usual, we then look at the difference, so our answer is <code>12 - 9 = 3</code>.</p>
<p class="codepen" data-height="450" data-default-tab="css,result" data-slug-hash="vYvEozM" data-user="danwilson" style="height: 450px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/vYvEozM">
CSS Math functions: rem() and mod() (Visual reference)</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>The New CSS Math: round()2023-08-17T00:00:00Zhttps://danielcwilson.com/posts/mathematicss-round/<p class="preamble">
CSS added many new Math functions to supplement the old favorites (such as <code>calc()</code>). They all ultimately represent a numeric value, but the nuance in how they work is not always clear from the start. <b>As of October 2023, these are available in the latest Safari and Firefox. They are also available in Edge/Chrome behind the Experimental Web Platform feature flag.</b>
</p>
<h3 id="the-basics-of-css-round()" tabindex="-1">The basics of CSS <code>round()</code> <a class="direct-link" href="https://danielcwilson.com/posts/mathematicss-round/#the-basics-of-css-round()" aria-hidden="true">#</a></h3>
<p>In JavaScript we have <code>Math.round()</code> which takes one numeric parameter, and the result will be the nearest integer. So <code>1.4</code> rounds down to <code>1</code> because it is closer to <code>1</code> than <code>2</code>. Similarly, <code>3.9</code> rounds up to <code>4</code> since that is the nearest integer.</p>
<pre class="language-js"><code class="language-js">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">round</span><span class="token punctuation">(</span><span class="token number">2.2</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 2</span><br />console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">round</span><span class="token punctuation">(</span><span class="token number">14.82</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 15</span><br />console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">round</span><span class="token punctuation">(</span><span class="token number">5.5</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 6</span></code></pre>
<p>With CSS, <code>round()</code> behaves similarly by default, except it takes two parameters. The first is the value you want to round, and the second is the precision number.</p>
<p>When you are thinking general math or JavaScript, the precision number would be <code>1</code> because we are always looking at integers, and we are expecting our answer to be a multiple of <code>1</code>. For CSS to have the straight equivalent of JavaScript’s <code>Math.round()</code>, we’d say <code>round(3.9, 1)</code>.</p>
<pre class="language-css"><code class="language-css"><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">round</span><span class="token punctuation">(</span>2.2<span class="token punctuation">,</span> 1<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 2 */</span><br /><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">round</span><span class="token punctuation">(</span>14.82<span class="token punctuation">,</span> 1<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 15 */</span><br /><span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">round</span><span class="token punctuation">(</span>5.5<span class="token punctuation">,</span> 1<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 6 */</span></code></pre>
<p><em>But... why do I need two parameters?</em></p>
<p>Since we are working with a variety of CSS units with various scales, the specification allows us to work in a manner that is most appropriate for our need.</p>
<p>Keeping it unitless for a bit longer, think about <code>opacity</code>. Its reasonable range is from <code>0</code> to <code>1</code>. Rounding here to an integer would always lead to a zero or one. This may be what you want, but maybe you want it with a different interval like the tenths place, such that your opacity is always one of 11 values: <code>0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1</code>. CSS rounding allows this, and you can specify it with precision of <code>0.1</code>. So instead of counting up by one, you count up by one tenth.</p>
<pre class="language-css"><code class="language-css"><span class="token property">opacity</span><span class="token punctuation">:</span> <span class="token function">round</span><span class="token punctuation">(</span>.56<span class="token punctuation">,</span> 0.1<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 0.6 */</span><br /><span class="token property">opacity</span><span class="token punctuation">:</span> <span class="token function">round</span><span class="token punctuation">(</span>.54<span class="token punctuation">,</span> 0.1<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 0.5 */</span></code></pre>
<p>We follow the same logic when considering units. Perhaps I want to always rotate an object at intervals of 45 degrees. I can set <code>45deg</code> as my precision unit to make sure my rotation is always a multiple of 45 degrees.</p>
<pre class="language-css"><code class="language-css"><span class="token property">rotate</span><span class="token punctuation">:</span> <span class="token function">round</span><span class="token punctuation">(</span>20deg<span class="token punctuation">,</span> 45deg<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 0deg */</span><br /><span class="token property">rotate</span><span class="token punctuation">:</span> <span class="token function">round</span><span class="token punctuation">(</span>30deg<span class="token punctuation">,</span> 45deg<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 45deg */</span><br /><span class="token property">rotate</span><span class="token punctuation">:</span> <span class="token function">round</span><span class="token punctuation">(</span>80deg<span class="token punctuation">,</span> 45deg<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 90deg */</span></code></pre>
<p>You can even mix units if they are of the same syntax. Other angle options exist beyond <code>deg</code> such as <code>turn</code> and <code>rad</code>, so we can use any of these in our function.</p>
<pre class="language-css"><code class="language-css"><span class="token property">rotate</span><span class="token punctuation">:</span> <span class="token function">round</span><span class="token punctuation">(</span>20deg<span class="token punctuation">,</span> .125turn<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 0deg */</span><br /><span class="token property">rotate</span><span class="token punctuation">:</span> <span class="token function">round</span><span class="token punctuation">(</span>80deg<span class="token punctuation">,</span> .125turn<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 90deg */</span></code></pre>
<h3 id="but-what-if-i-really-want-more-than-two-parameters" tabindex="-1">But what if I really want more than two parameters? <a class="direct-link" href="https://danielcwilson.com/posts/mathematicss-round/#but-what-if-i-really-want-more-than-two-parameters" aria-hidden="true">#</a></h3>
<p>CSS <code>round()</code> takes a third (optional) parameter at the start which allows you to specify a rounding strategy. The earlier examples are all using the default value of <code>nearest</code>. If you want this strategy, you can either leave out the strategy parameter or specify <code>nearest</code> explicitly.</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/* the following two both use the nearest strategy */</span><br /><span class="token property">rotate</span><span class="token punctuation">:</span> <span class="token function">round</span><span class="token punctuation">(</span>22.8deg<span class="token punctuation">,</span> 1deg<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 23deg */</span><br /><span class="token property">rotate</span><span class="token punctuation">:</span> <span class="token function">round</span><span class="token punctuation">(</span>nearest<span class="token punctuation">,</span> 22.8deg<span class="token punctuation">,</span> 1deg<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 23deg */</span></code></pre>
<p>If we instead want to always round up, we add a starting parameter to specify our rounding strategy as <code>up</code>. This will be similar to JavaScript’s <code>Math.ceil()</code>.</p>
<pre class="language-css"><code class="language-css"><span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token function">round</span><span class="token punctuation">(</span>up<span class="token punctuation">,</span> 20.01rem<span class="token punctuation">,</span> 1rem<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 21rem */</span><br /><span class="token property">rotate</span><span class="token punctuation">:</span> <span class="token function">round</span><span class="token punctuation">(</span>up<span class="token punctuation">,</span> 83deg<span class="token punctuation">,</span> 5deg<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 85deg */</span><br /><span class="token property">rotate</span><span class="token punctuation">:</span> <span class="token function">round</span><span class="token punctuation">(</span>up<span class="token punctuation">,</span> -83deg<span class="token punctuation">,</span> 5deg<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* -80deg */</span></code></pre>
<p>Similary, we can round down by specifying <code>round(down, ...)</code>, just as JavaScript allows with <code>Math.floor()</code>.</p>
<pre class="language-css"><code class="language-css"><span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token function">round</span><span class="token punctuation">(</span>down<span class="token punctuation">,</span> 20.999rem<span class="token punctuation">,</span> 1rem<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 20rem */</span><br /><span class="token property">rotate</span><span class="token punctuation">:</span> <span class="token function">round</span><span class="token punctuation">(</span>down<span class="token punctuation">,</span> 83deg<span class="token punctuation">,</span> 5deg<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 80deg */</span><br /><span class="token property">rotate</span><span class="token punctuation">:</span> <span class="token function">round</span><span class="token punctuation">(</span>down<span class="token punctuation">,</span> -83deg<span class="token punctuation">,</span> 5deg<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* -85deg */</span></code></pre>
<p>Finally, there is the <code>round(to-zero, ...)</code> strategy. This one behaves similar to <code>down</code> when working with positive numbers, but behaves as <code>up</code> for negative numbers. It will select the interval number that is closest to zero.</p>
<pre class="language-css"><code class="language-css"><span class="token property">rotate</span><span class="token punctuation">:</span> <span class="token function">round</span><span class="token punctuation">(</span>to-zero<span class="token punctuation">,</span> 83deg<span class="token punctuation">,</span> 5deg<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 80deg */</span><br /><span class="token property">rotate</span><span class="token punctuation">:</span> <span class="token function">round</span><span class="token punctuation">(</span>to-zero<span class="token punctuation">,</span> -83deg<span class="token punctuation">,</span> 5deg<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* -80deg */</span><br /><br /><span class="token property">rotate</span><span class="token punctuation">:</span> <span class="token function">round</span><span class="token punctuation">(</span>down<span class="token punctuation">,</span> 83deg<span class="token punctuation">,</span> 5deg<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 80deg */</span><br /><span class="token property">rotate</span><span class="token punctuation">:</span> <span class="token function">round</span><span class="token punctuation">(</span>down<span class="token punctuation">,</span> -83deg<span class="token punctuation">,</span> 5deg<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 85deg */</span><br /><span class="token property">rotate</span><span class="token punctuation">:</span> <span class="token function">round</span><span class="token punctuation">(</span>up<span class="token punctuation">,</span> -83deg<span class="token punctuation">,</span> 5deg<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 80deg */</span></code></pre>
<p class="codepen" data-height="450" data-default-tab="css,result" data-slug-hash="vYQMEgp" data-user="danwilson" style="height: 450px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/vYQMEgp">
CSS Math round(): angles (Visual Reference)</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>Cutouts with Clip Paths2023-04-03T00:00:00Zhttps://danielcwilson.com/posts/clip-path-cutouts/<p>Clip paths (and more generally, the shape building functions offered by <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Shapes/Basic_Shapes">CSS Shapes</a>) provide mechanisms to turn our rectangular elements into other basic shapes.</p>
<p>With a little extra planning, we can also use clip paths to perform cutouts inside a shape, as seen in this example. The entire Speak and Spell device is made within a single div using (a lot of) box shadows and background gradients... and one clip path to cut out space for the handle. This allows the background of the webpage to be seen from within the element.</p>
<p class="codepen" data-height="515" data-default-tab="result" data-slug-hash="QWBaRvp" data-user="danwilson" style="height: 515px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/QWBaRvp">
Single Div Speak & Spell (Has Sound)</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<h3 id="getting-a-single-cutout-shape" tabindex="-1">Getting a single cutout shape <a class="direct-link" href="https://danielcwilson.com/posts/clip-path-cutouts/#getting-a-single-cutout-shape" aria-hidden="true">#</a></h3>
<p>With <code>clip-path: polygon()</code> we can cut an element to any arbitrary polygon. For example, we can turn a rectangular <code>div</code> into a triangle by specifying three points (vertices) for our polygon.</p>
<pre class="language-js"><code class="language-js">div <span class="token punctuation">{</span><br /> clip<span class="token operator">-</span>path<span class="token operator">:</span> <span class="token function">polygon</span><span class="token punctuation">(</span><br /> <span class="token number">50</span><span class="token operator">%</span> <span class="token number">0</span><span class="token operator">%</span><span class="token punctuation">,</span><br /> <span class="token number">0</span><span class="token operator">%</span> <span class="token number">100</span><span class="token operator">%</span><span class="token punctuation">,</span><br /> <span class="token number">100</span><span class="token operator">%</span> <span class="token number">100</span><span class="token operator">%</span><br /> <span class="token punctuation">)</span><br /><span class="token punctuation">}</span></code></pre>
<p>To instead cut out a triangle on the inside, we need our clip path to:</p>
<ol>
<li>Outline the full element</li>
<li>Go to the starting point for the cutout shape</li>
<li>Make the cutout shape</li>
<li>Close the cutout shape by confirming you connected back to your starting point</li>
</ol>
<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="RwYegOr" data-editable="true" data-user="danwilson" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/RwYegOr">
Clip Path Cutouts</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<pre class="language-js"><code class="language-js"><span class="token punctuation">.</span>inside<span class="token operator">-</span>cutout <span class="token punctuation">{</span><br /> clip<span class="token operator">-</span>path<span class="token operator">:</span> <span class="token function">polygon</span><span class="token punctuation">(</span><br /> evenodd<span class="token punctuation">,</span><br /> <span class="token comment">/*surround element first*/</span><br /> <span class="token number">0</span><span class="token operator">%</span> <span class="token number">0</span><span class="token operator">%</span><span class="token punctuation">,</span><br /> <span class="token number">0</span><span class="token operator">%</span> <span class="token number">100</span><span class="token operator">%</span><span class="token punctuation">,</span><br /> <span class="token number">100</span><span class="token operator">%</span> <span class="token number">100</span><span class="token operator">%</span><span class="token punctuation">,</span><br /> <span class="token number">100</span><span class="token operator">%</span> <span class="token number">0</span><span class="token operator">%</span><span class="token punctuation">,</span><br /> <span class="token number">0</span><span class="token operator">%</span> <span class="token number">0</span><span class="token operator">%</span><span class="token punctuation">,</span><br /> <br /> <span class="token comment">/* cut interior triangle */</span><br /> <span class="token number">50</span><span class="token operator">%</span> <span class="token number">5</span><span class="token operator">%</span><span class="token punctuation">,</span> <span class="token comment">/* point 1: near the top center */</span><br /> <span class="token number">5</span><span class="token operator">%</span> <span class="token number">95</span><span class="token operator">%</span><span class="token punctuation">,</span> <span class="token comment">/* point 2: near the bottom left corner */</span><br /> <span class="token number">95</span><span class="token operator">%</span> <span class="token number">95</span><span class="token operator">%</span><span class="token punctuation">,</span> <span class="token comment">/* point 3: near the bottom right corner */</span><br /> <span class="token number">50</span><span class="token operator">%</span> <span class="token number">5</span><span class="token operator">%</span> <span class="token comment">/* connect back to point 1 of triangle */</span><br /> <span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>This polygon also uses a <a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill-rule">fill rule</a> to the clip path, by setting the first parameter on the polygon to <code>evenodd</code>. This setting allows us to make cuts inside other shapes.</p>
<h3 id="nesting-cutouts" tabindex="-1">Nesting cutouts <a class="direct-link" href="https://danielcwilson.com/posts/clip-path-cutouts/#nesting-cutouts" aria-hidden="true">#</a></h3>
<p>We can effectively nesting our shapes multiple times if we keep making successive cuts into our cutout. With <code>evenodd</code> as our fill rule, we can alternate between clipped and non-clipped areas. The secret is to always start at a consistant point (start a shape, make the shape, close the shape by connecting to the start, and then moving the next point into the inside of the shape), we can create nested clip paths.</p>
<p>By also using CSS Custom Properties, we can create straightforward animations by changing the points. This example additionally uses CSS Trigonometric functions, so by only changing a set of radius custom properties representing each pentagon’s dimensions, we can alternate between a nested collection of pentagons to a fully filled pentagon on hover.</p>
<p class="codepen" data-height="404" data-default-tab="css,result" data-slug-hash="xxaooaK" data-user="danwilson" style="height: 404px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/xxaooaK">
Nested Pentagons</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<h3 id="cutting-out-multiple-shapes-and-curves" tabindex="-1">Cutting out multiple shapes and curves <a class="direct-link" href="https://danielcwilson.com/posts/clip-path-cutouts/#cutting-out-multiple-shapes-and-curves" aria-hidden="true">#</a></h3>
<p>With trigonometric functions in CSS we can also [introduce curves]](/posts/css-shapes-with-trig-functions) beyond basic circles and ellipses. These approaches can be applied on the inside of a shape as well (as in our initial <a href="https://codepen.io/danwilson/full/QWBaRvp">Speak and Spell</a> example).</p>
<p>We can make a cutout smiley face by surrounding our element fully, entering inside to make one eye, connecting to a second eye, connecting to a mouth, and connecting back to our initial entry point. When dealing with multiple shapes the biggest concerns are making sure you close each shape and connect back along the same line you used to move to the new shape.</p>
<p class="codepen" data-height="515" data-default-tab="css,result" data-slug-hash="oNPoXEo" data-user="danwilson" style="height: 515px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/oNPoXEo">
Curved Cutouts with Clip Paths & CSS Trig Functions</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>When dealing with very long polygon definitions, it can be hard to figure out where specifically an error is when things are not lining up as expected. Take it step by step, and isolate it in a tool that helps with reloading on change (like CodePen) to quickly add or remove points and see the changes in real time.</p>
Improving CSS Shapes with Trigonometric Functions2023-03-28T00:00:00Zhttps://danielcwilson.com/posts/css-shapes-with-trig-functions/<p class="preamble">CSS Trigonometric functions are supported in the latest versions of Safari, Firefox, Edge, and Chrome. We also discuss animation via <code>@property</code>, which is supported in the latest Safari, Edge, and Chrome (as of this writing).</p>
<p>The CSS Shapes specification enabled a lot to make <a href="https://24ways.org/2018/clip-paths-know-no-bounds/">interesting shapes</a> on the web today, via <code>clip-path</code>, <code>shape-outside</code>, and more. With the introduction of CSS Trigonometric functions, we can simplify how we make regular polygons and build even more complex shapes by more easily approximating curves.</p>
<p>Even though what we discuss will apply to more, we will focus this discussion applying trigonometry to the <code>clip-path</code> property. We will start with an overview of how to work with <a href="https://danielcwilson.com/posts/css-shapes-with-trig-functions/#css-shapes-basics">basic clip paths</a> and a quick discussion on the <a href="https://danielcwilson.com/posts/css-shapes-with-trig-functions/#how-to-create-a-regular-polygon-with-trigonometric-functions">math side of trigonometry</a>. However, you can always skip to where we <a href="https://danielcwilson.com/posts/css-shapes-with-trig-functions/#how-to-create-a-regular-polygon-with-css">combine trigonometric functions and clip paths</a> and dig into the demos.</p>
<h3 id="css-shapes-basics" tabindex="-1">CSS Shapes Basics <a class="direct-link" href="https://danielcwilson.com/posts/css-shapes-with-trig-functions/#css-shapes-basics" aria-hidden="true">#</a></h3>
<p>With clip paths and Basic Shapes functions, we can take our rectangular elements and define a shape where only portions of our element will be visible. There are a few key functions, but <code>circle()</code>, <code>ellipse()</code>, and <code>polygon()</code> are likely the most straightforward ways to clip to basic shapes.</p>
<p>As the names state, we can create rounded clips via <code>circle</code> and <code>ellipse</code>, and we are able to clip our element to any polygon shape with <code>polygon()</code> by passing in a collection of coordinates. Any valid length or percentage can be used to define the radius and center points for circles and ellipses, as well as for coordinates within polygons.</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/* circle with a 2rem radius, at center of element */</span><br /><span class="token property">clip-path</span><span class="token punctuation">:</span> <span class="token function">circle</span><span class="token punctuation">(</span>2rem<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token comment">/* circle with a 20% radius, centered on the right side, offset slightly at the top*/</span><br /><span class="token property">clip-path</span><span class="token punctuation">:</span> <span class="token function">circle</span><span class="token punctuation">(</span>20% at 100% 1rem<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token comment">/* tall ellipse, at center of element */</span><br /><span class="token property">clip-path</span><span class="token punctuation">:</span> <span class="token function">ellipse</span><span class="token punctuation">(</span>20% 50%<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<pre class="language-css"><code class="language-css"><span class="token comment">/* rectangle */</span><br /><span class="token property">clip-path</span><span class="token punctuation">:</span> <span class="token function">polygon</span><span class="token punctuation">(</span><br /> 0% 20%<span class="token punctuation">,</span><br /> 100% 20%<span class="token punctuation">,</span><br /> 0% 60%<span class="token punctuation">,</span><br /> 100% 60%<br /><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">/* triangle with base aligned to the bottom of element */</span><br /><span class="token property">clip-path</span><span class="token punctuation">:</span> <span class="token function">polygon</span><span class="token punctuation">(</span><br /> 50% 0%<span class="token punctuation">,</span><br /> 0% 100%<span class="token punctuation">,</span><br /> 100% 100%<br /><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p class="codepen" data-height="345" data-default-tab="css,result" data-slug-hash="XWPOJMY" data-user="danwilson" style="height: 345px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/XWPOJMY">
Clip Path Gallery</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>As long as you can determine an <code>X,Y</code> coordinate for each point on your polygon, you can build impressive <code>clip-path</code> definitions.</p>
<p>While we get a lot with these basic shape tools, there are still limitations to what can reasonably be built with clip paths (and CSS Shapes in general):</p>
<ol>
<li>You can only use one shape function (a list of clip path functions to be combined is not supported by the property)</li>
<li>An ellipse can only be vertical or horizontal (no diagonal ellipses or rotations)</li>
<li>You cannot easily create shapes with curves (except for the single circle, single ellipse, or a single rounded rectangle)</li>
<li>To build arbitrary polygons, a non-trivial amount of JavaScript or other calculations might be necessary to end up with properly mapped coordinates</li>
</ol>
<h3 id="advancing-css-shapes-with-advanced-css" tabindex="-1">Advancing CSS Shapes with Advanced CSS <a class="direct-link" href="https://danielcwilson.com/posts/css-shapes-with-trig-functions/#advancing-css-shapes-with-advanced-css" aria-hidden="true">#</a></h3>
<p>Now, I will admit I forgot almost everything about trigonometry in recent years, but it might be time to relearn some things with the introduction of CSS Trigonometric functions. Using angles, sine, cosine, and more can help with positioning, animations, and... drawing shapes.</p>
<p>For this next example, I took two attempts to make a regular pentagon (a five-sided polygon where each side is of equal length). For the first pentagon, I didn’t use equations, I just typed in 5 different coordinates repeatedly until I got something that was close visually. Once I felt pretty good about it, I took another try using the some of the new trigonometric functions <code>sin()</code> and <code>cos()</code> available in CSS. The second pentagon is in fact a regular pentagon.</p>
<p class="codepen" data-height="323" data-default-tab="css,result" data-slug-hash="GRXzgPj" data-user="danwilson" style="height: 323px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/GRXzgPj">
Clip Path Gallery</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>Before we dig into the <a href="https://danielcwilson.com/posts/css-shapes-with-trig-functions/#how-to-create-a-regular-polygon-with-css">CSS specifics</a>, let’s focus on the mathematics first.</p>
<h4 id="how-to-create-a-regular-polygon-with-trigonometric-functions" tabindex="-1">How to create a regular polygon with trigonometric functions <a class="direct-link" href="https://danielcwilson.com/posts/css-shapes-with-trig-functions/#how-to-create-a-regular-polygon-with-trigonometric-functions" aria-hidden="true">#</a></h4>
<p>To make a regular polygon, you can place points equidistantly around a circle and connect them with straight lines. So for a pentagon, we can place five points around a circle with a known radius. Since a circle is 360 degrees around, we can place them at 72 degree intervals (the equation to determine the angle interval is <code>n/360</code> where <code>n</code> is the number of sides).</p>
<p>But... we are dealing with coordinates and two axes (<code>x</code> and <code>y</code>). So how do we place points around a circle based on an angle and a radius?</p>
<p>In a traditional coordinate system, the function <code>cos(<angle>)</code> helps us determine the <code>x</code> value of our coordinate when combined with a radius. Similarly, <code>sin(<angle>)</code> and the radius will be used to determine the <code>y</code> value.</p>
<p class="codepen" data-height="405" data-default-tab="result" data-slug-hash="jOvdPyv" data-user="danwilson" style="height: 405px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/jOvdPyv">
Visual Reference: Traditional Coordinate System</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>The radius of our circle becomes the hypotenuse of a right triangle (don’t you just love reliving all these mathematical terms?) at any point along the circle’s surface.</p>
<p>To determine <code>x</code>: <code>x = cos(<angle>) * radius</code></p>
<p>To determine <code>y</code>: <code>y = sin(<angle>) * radius</code></p>
<p>A regular pentagon then becomes a collection of five coordinates, where the angles used in the trigonometric functions are 72 degrees apart. For a radius of 1cm:</p>
<pre><code>(cos(0deg) * 1cm) (sin(0deg) * 1cm),
(cos(72deg) * 1cm) (sin(72deg) * 1cm),
(cos(144deg) * 1cm) (sin(144deg) * 1cm),
(cos(216deg) * 1cm) (sin(216deg) * 1cm),
(cos(288deg) * 1cm) (sin(288deg) * 1cm)
</code></pre>
<h4 id="how-to-create-a-regular-polygon-with-css" tabindex="-1">How to create a regular polygon with CSS <a class="direct-link" href="https://danielcwilson.com/posts/css-shapes-with-trig-functions/#how-to-create-a-regular-polygon-with-css" aria-hidden="true">#</a></h4>
<p>The hard work is behind us and now we can discuss how to use this in CSS.</p>
<p>As far as CSS and trigonometry are concerned, our previous example is valid CSS once we put it inside a <code>polygon()</code> and some <code>calc()</code>s:</p>
<pre class="language-css"><code class="language-css"><span class="token property">clip-path</span><span class="token punctuation">:</span> <span class="token function">polygon</span><span class="token punctuation">(</span><br /> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">cos</span><span class="token punctuation">(</span>0deg<span class="token punctuation">)</span> * 1cm<span class="token punctuation">)</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">sin</span><span class="token punctuation">(</span>0deg<span class="token punctuation">)</span> * 1cm<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">cos</span><span class="token punctuation">(</span>72deg<span class="token punctuation">)</span> * 1cm<span class="token punctuation">)</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">sin</span><span class="token punctuation">(</span>72deg<span class="token punctuation">)</span> * 1cm<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">cos</span><span class="token punctuation">(</span>144deg<span class="token punctuation">)</span> * 1cm<span class="token punctuation">)</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">sin</span><span class="token punctuation">(</span>144deg<span class="token punctuation">)</span> * 1cm<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">cos</span><span class="token punctuation">(</span>216deg<span class="token punctuation">)</span> * 1cm<span class="token punctuation">)</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">sin</span><span class="token punctuation">(</span>216deg<span class="token punctuation">)</span> * 1cm<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">cos</span><span class="token punctuation">(</span>288deg<span class="token punctuation">)</span> * 1cm<span class="token punctuation">)</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">sin</span><span class="token punctuation">(</span>288deg<span class="token punctuation">)</span> * 1cm<span class="token punctuation">)</span><br /><span class="token punctuation">)</span></code></pre>
<p>Those five points give us a similar regular pentagon to our earlier pentagon side-by-side example... almost.</p>
<p class="codepen" data-height="300" data-default-tab="result" data-slug-hash="PodVqLa" data-user="danwilson" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/PodVqLa">
Clip Path Gallery (Pentagon)</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>We have two primary considerations to think about when moving from the traditional coordinate system to one on our device screens</p>
<ol>
<li><code>0,0</code> on our element is the top left corner (regardless of writing mode, etc.)</li>
<li>The <code>y</code> values goes positive as you move <em>down</em> the axis</li>
</ol>
<p>So when dealing with clip paths, if we want our shape to be centered in our element, we need to offset our center point by <code>50%</code>. And depending on the orientation we want, it may be useful to multiply some <code>y</code> values by <code>-1</code>. In this case, our main desire is to get the element centered, so we can modify our definition with:</p>
<pre class="language-css"><code class="language-css"><span class="token property">clip-path</span><span class="token punctuation">:</span> <span class="token function">polygon</span><span class="token punctuation">(</span><br /> <span class="token function">calc</span><span class="token punctuation">(</span>50% + <span class="token function">cos</span><span class="token punctuation">(</span>0deg<span class="token punctuation">)</span> * 1cm<span class="token punctuation">)</span> <span class="token function">calc</span><span class="token punctuation">(</span>50% + <span class="token function">sin</span><span class="token punctuation">(</span>0deg<span class="token punctuation">)</span> * 1cm<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">calc</span><span class="token punctuation">(</span>50% + <span class="token function">cos</span><span class="token punctuation">(</span>72deg<span class="token punctuation">)</span> * 1cm<span class="token punctuation">)</span> <span class="token function">calc</span><span class="token punctuation">(</span>50% + <span class="token function">sin</span><span class="token punctuation">(</span>72deg<span class="token punctuation">)</span> * 1cm<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">calc</span><span class="token punctuation">(</span>50% + <span class="token function">cos</span><span class="token punctuation">(</span>144deg<span class="token punctuation">)</span> * 1cm<span class="token punctuation">)</span> <span class="token function">calc</span><span class="token punctuation">(</span>50% + <span class="token function">sin</span><span class="token punctuation">(</span>144deg<span class="token punctuation">)</span> * 1cm<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">calc</span><span class="token punctuation">(</span>50% + <span class="token function">cos</span><span class="token punctuation">(</span>216deg<span class="token punctuation">)</span> * 1cm<span class="token punctuation">)</span> <span class="token function">calc</span><span class="token punctuation">(</span>50% + <span class="token function">sin</span><span class="token punctuation">(</span>216deg<span class="token punctuation">)</span> * 1cm<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">calc</span><span class="token punctuation">(</span>50% + <span class="token function">cos</span><span class="token punctuation">(</span>288deg<span class="token punctuation">)</span> * 1cm<span class="token punctuation">)</span> <span class="token function">calc</span><span class="token punctuation">(</span>50% + <span class="token function">sin</span><span class="token punctuation">(</span>288deg<span class="token punctuation">)</span> * 1cm<span class="token punctuation">)</span><br /><span class="token punctuation">)</span></code></pre>
<p>Let’s assume for the next few examples (as the CodePen demos do) that our element we are clipping is a square shape. We are still using <code>1cm</code> so far, but for our pentagon to maximize inside our square element, we really should be using a radius of <code>50%</code> since that will allow us to use as much space as possible inside our element. To be flexible going forward, we can make it straightforward to change our center point and radius by using CSS Custom Properties:</p>
<pre class="language-css"><code class="language-css"><span class="token property">--radius</span><span class="token punctuation">:</span> 50%<span class="token punctuation">;</span><br /><span class="token property">--center-x</span><span class="token punctuation">:</span> 50%<span class="token punctuation">;</span><br /><span class="token property">--center-y</span><span class="token punctuation">:</span> 50%<span class="token punctuation">;</span><br /><span class="token property">clip-path</span><span class="token punctuation">:</span> <span class="token function">polygon</span><span class="token punctuation">(</span><br /> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--center-x<span class="token punctuation">)</span> + <span class="token function">cos</span><span class="token punctuation">(</span>0deg<span class="token punctuation">)</span> * <span class="token function">var</span><span class="token punctuation">(</span>--radius<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--center-y<span class="token punctuation">)</span> + <span class="token function">sin</span><span class="token punctuation">(</span>0deg<span class="token punctuation">)</span> * <span class="token function">var</span><span class="token punctuation">(</span>--radius<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--center-x<span class="token punctuation">)</span> + <span class="token function">cos</span><span class="token punctuation">(</span>72deg<span class="token punctuation">)</span> * <span class="token function">var</span><span class="token punctuation">(</span>--radius<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--center-y<span class="token punctuation">)</span> + <span class="token function">sin</span><span class="token punctuation">(</span>72deg<span class="token punctuation">)</span> * <span class="token function">var</span><span class="token punctuation">(</span>--radius<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--center-x<span class="token punctuation">)</span> + <span class="token function">cos</span><span class="token punctuation">(</span>144deg<span class="token punctuation">)</span> * <span class="token function">var</span><span class="token punctuation">(</span>--radius<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--center-y<span class="token punctuation">)</span> + <span class="token function">sin</span><span class="token punctuation">(</span>144deg<span class="token punctuation">)</span> * <span class="token function">var</span><span class="token punctuation">(</span>--radius<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--center-x<span class="token punctuation">)</span> + <span class="token function">cos</span><span class="token punctuation">(</span>216deg<span class="token punctuation">)</span> * <span class="token function">var</span><span class="token punctuation">(</span>--radius<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--center-y<span class="token punctuation">)</span> + <span class="token function">sin</span><span class="token punctuation">(</span>216deg<span class="token punctuation">)</span> * <span class="token function">var</span><span class="token punctuation">(</span>--radius<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--center-x<span class="token punctuation">)</span> + <span class="token function">cos</span><span class="token punctuation">(</span>288deg<span class="token punctuation">)</span> * <span class="token function">var</span><span class="token punctuation">(</span>--radius<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--center-y<span class="token punctuation">)</span> + <span class="token function">sin</span><span class="token punctuation">(</span>288deg<span class="token punctuation">)</span> * <span class="token function">var</span><span class="token punctuation">(</span>--radius<span class="token punctuation">)</span><span class="token punctuation">)</span><br /><span class="token punctuation">)</span></code></pre>
<p>This is admittedly a fairly long property value to specify five points for a polygon. But we did not have to do any calculations or figure coordinates out visually, we were able to lean on math and put the equations directly in our CSS. And if we want to make small adjustments like change the center point or radius, we do not have to go recalculate all the coordinates and hardcode them.</p>
<p>Another key benefit to using CSS trigonometric functions is that they can be used with any valid CSS angle, whether that is in degrees, radians, turns, or other options. So we could instead define our pentagon in the <code>turn</code> unit:</p>
<pre class="language-css"><code class="language-css"><span class="token property">clip-path</span><span class="token punctuation">:</span> <span class="token function">polygon</span><span class="token punctuation">(</span><br /> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--center-x<span class="token punctuation">)</span> + <span class="token function">cos</span><span class="token punctuation">(</span>0turn<span class="token punctuation">)</span> * <span class="token function">var</span><span class="token punctuation">(</span>--radius<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--center-y<span class="token punctuation">)</span> + <span class="token function">sin</span><span class="token punctuation">(</span>0deg<span class="token punctuation">)</span> * <span class="token function">var</span><span class="token punctuation">(</span>--radius<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--center-x<span class="token punctuation">)</span> + <span class="token function">cos</span><span class="token punctuation">(</span>.2turn<span class="token punctuation">)</span> * <span class="token function">var</span><span class="token punctuation">(</span>--radius<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--center-y<span class="token punctuation">)</span> + <span class="token function">sin</span><span class="token punctuation">(</span>.2turn<span class="token punctuation">)</span> * <span class="token function">var</span><span class="token punctuation">(</span>--radius<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--center-x<span class="token punctuation">)</span> + <span class="token function">cos</span><span class="token punctuation">(</span>.4turn<span class="token punctuation">)</span> * <span class="token function">var</span><span class="token punctuation">(</span>--radius<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--center-y<span class="token punctuation">)</span> + <span class="token function">sin</span><span class="token punctuation">(</span>.4turn<span class="token punctuation">)</span> * <span class="token function">var</span><span class="token punctuation">(</span>--radius<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--center-x<span class="token punctuation">)</span> + <span class="token function">cos</span><span class="token punctuation">(</span>.6turn<span class="token punctuation">)</span> * <span class="token function">var</span><span class="token punctuation">(</span>--radius<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--center-y<span class="token punctuation">)</span> + <span class="token function">sin</span><span class="token punctuation">(</span>.6turn<span class="token punctuation">)</span> * <span class="token function">var</span><span class="token punctuation">(</span>--radius<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--center-x<span class="token punctuation">)</span> + <span class="token function">cos</span><span class="token punctuation">(</span>.8turn<span class="token punctuation">)</span> * <span class="token function">var</span><span class="token punctuation">(</span>--radius<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--center-y<span class="token punctuation">)</span> + <span class="token function">sin</span><span class="token punctuation">(</span>.8turn<span class="token punctuation">)</span> * <span class="token function">var</span><span class="token punctuation">(</span>--radius<span class="token punctuation">)</span><span class="token punctuation">)</span><br /><span class="token punctuation">)</span></code></pre>
<p>The added flexibility of the additional angle units is refreshing, especially after working with the JavaScript trigonometry equivalents such as <code>Math.sin()</code> which only accept radians for the parameter.</p>
<p>As a bonus, animation also becomes more direct in browsers that support <code>@property</code> (and thus can enable interpolation on the custom property value, independent from the overall <code>clip-path</code> value):</p>
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="JjaxYGJ" data-user="danwilson" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/JjaxYGJ">
Clip Path Gallery (animated)</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<h3 id="approximating-rounded-and-curved-shapes" tabindex="-1">Approximating rounded and curved shapes <a class="direct-link" href="https://danielcwilson.com/posts/css-shapes-with-trig-functions/#approximating-rounded-and-curved-shapes" aria-hidden="true">#</a></h3>
<p>With the help of trigonometry (and admittedly longer clip path values), we can approximate curves to make even more interesting possibilities</p>
<p>Now that we know we can build regular polygons along a circle with trigonometry, we can use that to make polygons with a large amount of sides to create what ultimately appear to be circles or ellipses. For most elements on a page on a large computer monitor, a 60-sided regular polygon will be more than enough sides to make (an approximation of) a circle. Depending on the size of the element, the straight edges likely will not even be visible, so the curve will appear fairly smooth. If you need to can add more sides to the polygon to make it appear more circular.</p>
<p class="codepen" data-height="368" data-default-tab="js,result" data-slug-hash="bGxzYqJ" data-user="danwilson" style="height: 368px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/bGxzYqJ">
Approximating a Circle</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>And with this capability, we can start to do more with circles, curves, straight edges, and mixing them all together.</p>
<p>We are no longer limited to one circle. So we can build a shape that has the appearance of a snowperson, with two circles overlapping each other.</p>
<p class="codepen" data-height="396" data-default-tab="css,result" data-slug-hash="PodVOdg" data-user="danwilson" style="height: 396px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/PodVOdg">
Building a Snowperson (as clip-path)</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>We also can plot out a rotated ellipse (remember that using the <code>ellipse()</code> function will only produce ellipses that are vertical or horizontal). This takes some advanced calculations, but any time there is an equation, it can translate directly to our CSS property value. A little search on the internet led me to an answer to the <a href="https://math.stackexchange.com/a/2647450">equations necessary</a>, which then led to the following CSS pattern <em>for each coordinate</em>:</p>
<pre class="language-css"><code class="language-css"><span class="token property">clip-path</span><span class="token punctuation">:</span> <span class="token function">polygon</span><span class="token punctuation">(</span><br /> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--center-x<span class="token punctuation">)</span> + <span class="token punctuation">(</span><span class="token function">cos</span><span class="token punctuation">(</span>0deg<span class="token punctuation">)</span> * <span class="token function">cos</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--rotation<span class="token punctuation">)</span><span class="token punctuation">)</span> * <span class="token function">var</span><span class="token punctuation">(</span>--radius-x<span class="token punctuation">)</span><span class="token punctuation">)</span> - <span class="token punctuation">(</span><span class="token function">sin</span><span class="token punctuation">(</span>0deg<span class="token punctuation">)</span> * <span class="token function">sin</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--rotation<span class="token punctuation">)</span><span class="token punctuation">)</span> * <span class="token function">var</span><span class="token punctuation">(</span>--radius-y<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br /> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--center-y<span class="token punctuation">)</span> + <span class="token punctuation">(</span><span class="token function">cos</span><span class="token punctuation">(</span>0deg<span class="token punctuation">)</span> * <span class="token function">sin</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--rotation<span class="token punctuation">)</span><span class="token punctuation">)</span> * <span class="token function">var</span><span class="token punctuation">(</span>--radius-x<span class="token punctuation">)</span><span class="token punctuation">)</span> + <span class="token punctuation">(</span><span class="token function">sin</span><span class="token punctuation">(</span>0deg<span class="token punctuation">)</span> * <span class="token function">cos</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--rotation<span class="token punctuation">)</span><span class="token punctuation">)</span> * <span class="token function">var</span><span class="token punctuation">(</span>--radius-y<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token comment">/* followed by many more coordinates */</span><br /><span class="token punctuation">)</span><br /><br /><span class="token property">--rotation</span><span class="token punctuation">:</span> .1turn<span class="token punctuation">;</span><br /><span class="token property">--radius-x</span><span class="token punctuation">:</span> 20%<span class="token punctuation">;</span><br /><span class="token property">--radius</span><span class="token punctuation">:</span> 50%<span class="token punctuation">;</span><br /><span class="token property">--center-x</span><span class="token punctuation">:</span> 50%<span class="token punctuation">;</span><br /><span class="token property">--center-y</span><span class="token punctuation">:</span> 50%<span class="token punctuation">;</span></code></pre>
<p>As discussed before, nothing here is brief. I am even still using JavaScript in this case to generate the clip path as a convenience:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">generateRotatedEllipse</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> points <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br /><br /> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> <span class="token number">360</span><span class="token punctuation">;</span> i <span class="token operator">=</span> i <span class="token operator">+</span> <span class="token number">6</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> points<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">calc(var(--center-x) + (cos(</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>i<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">deg) * cos(var(--rotation)) * var(--radius-x)) - (sin(</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>i<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">deg) * sin(var(--rotation)) * var(--radius-y)))<br /> calc(var(--center-y) + (cos(</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>i<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">deg) * sin(var(--rotation)) * var(--radius-x)) + (sin(</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>i<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">deg) * cos(var(--rotation)) * var(--radius-y)))</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><br /> <span class="token keyword">const</span> ellipse <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">".rotated-ellipse"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> ellipse<span class="token punctuation">.</span>style<span class="token punctuation">.</span>clipPath <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">polygon(</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>points<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">","</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">)</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>But keeping the math calculation in CSS and combine it with CSS Custom Properties gives us a flexible way to build clip paths and update them in the future... or in an animation (as seen in <a href="https://codepen.io/danwilson/pen/vYzbYzv">this ellipse demo</a> if your browser supports <code>@property</code>):</p>
<p class="codepen" data-height="362" data-default-tab="css,result" data-slug-hash="vYzbYzv" data-user="danwilson" style="height: 362px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/vYzbYzv">
Spinning Elliptical Reveal (via clip-path and @property)</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<h3 id="explore-the-gallery" tabindex="-1">Explore the gallery <a class="direct-link" href="https://danielcwilson.com/posts/css-shapes-with-trig-functions/#explore-the-gallery" aria-hidden="true">#</a></h3>
<p>We have a lot of ways to work with CSS Shapes, and we have a lot more to explore as CSS continues to increase in capabilities.</p>
<p class="codepen" data-height="366" data-default-tab="css,result" data-slug-hash="qBMvveV" data-user="danwilson" style="height: 366px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/qBMvveV">
Clip Path Gallery</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
Mixing Device Cameras and the Web2021-11-11T11:48:30Zhttps://danielcwilson.com/blog/2021/11/user-media/<p class="preamble">During this article there will be several examples that require access to your camera. This API is a web standard, and the demos in this article will only have access to video streams if you opt in and allow access. Camera data is only available/visible to you and nothing is saved by this article or its demos.</p>
<p>We are fairly used to the apps on our mobile devices and computers to have access to cameras and microphones for grabbing a selfie or joining a video call. These same media inputs are accessible to our web applications via the <a href="https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices">Media Devices API</a>. We will be focusing on video input specifically to explore how this API can be used creatively with other web technology.</p>
<p>To follow along with the demo, please view this article on a device with a camera and allow access.</p>
<div class="demo-section starter">
<h4>Demo</h4>
<button type="button" id="allow-access" class="allower">Start camera</button>
<button type="button" id="revoke-access" class="revoker">Remove access</button>
</div>
<h3 id="the-quick-path-to-loading-a-video-stream" tabindex="-1">The quick path to loading a video stream <a class="direct-link" href="https://danielcwilson.com/blog/2021/11/user-media/#the-quick-path-to-loading-a-video-stream" aria-hidden="true">#</a></h3>
<p>At its core, use of the camera consists of an API call to access the device camera’s video stream and an HTML element (such as <code>video</code> or <code>canvas</code>) to send the stream for viewing.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>video</span> <span class="token attr-name">playsinline</span> <span class="token attr-name">muted</span> <span class="token attr-name">autoplay</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>video</span><span class="token punctuation">></span></span></code></pre>
<pre class="language-js"><code class="language-js"><span class="token keyword">let</span> stream<span class="token punctuation">;</span><br /><span class="token keyword">if</span> <span class="token punctuation">(</span>navigator<span class="token punctuation">.</span>mediaDevices <span class="token operator">&&</span> navigator<span class="token punctuation">.</span>mediaDevices<span class="token punctuation">.</span>getUserMedia<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> stream <span class="token operator">=</span> <span class="token keyword">await</span> navigator<span class="token punctuation">.</span>mediaDevices<span class="token punctuation">.</span><span class="token function">getUserMedia</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br /> <span class="token literal-property property">video</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">audio</span><span class="token operator">:</span> <span class="token boolean">false</span><br /> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">const</span> vid <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'video'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> vid<span class="token punctuation">.</span>srcObject <span class="token operator">=</span> stream<span class="token punctuation">;</span><br /> vid<span class="token punctuation">.</span><span class="token function-variable function">onloadedmetadata</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> vid<span class="token punctuation">.</span><span class="token function">play</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>Let’s break down each step of that example</p>
<ol>
<li>We create an empty video element (with a few attributes to guide the browser that our video will be friendly to a user, such as not use sound to start)</li>
<li>In the JavaScript, we first check for presence of the Media Devices API and its <code>getUserMedia</code> method. This is the primary method we deal with when working with video. It also requires <code>https</code>, so sites on plain <code>http</code> will also not have access to this API. Feature detection is key with all things Media Devices, as every OS + browser + camera combination will be (at least a little) different.</li>
<li>Once we know there is support, we ask the user if we can stream data from their device by calling <code>getUserMedia</code> with an options object that tells specifically what we are requesting. In this case we are telling the browser we want the default video stream that it can find, but we do not want any microphone access.</li>
<li>This method returns a Promise, and if the user allows access, we</li>
</ol>
<ul>
<li>Receive the video stream</li>
<li>Set the video stream as our <code>video</code> element’s source</li>
<li>Play the stream once it is loaded and ready</li>
</ul>
<p>As this is permission based, a user can always reject permission. The user should be given enough information about why video access is being requested before it happens so they can make the best choice for them.</p>
<h3 id="what-can-i-do-with-this-api" tabindex="-1">What can I do with this API? <a class="direct-link" href="https://danielcwilson.com/blog/2021/11/user-media/#what-can-i-do-with-this-api" aria-hidden="true">#</a></h3>
<p>There are straightforward reasons why media device access made it to the web, such as it enables videoconferencing. Access to the microphone also opens up possibilities with <a href="https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition">Speech Recognition</a>. There are even ways to enable screen sharing through a similar Media Devices API (<a href="https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia"><code>getDisplayMedia()</code></a>).</p>
<figure>
<img src="https://danielcwilson.com/img/posts/2021/photobooth.jpg" style="aspect-ratio: 1334 / 750" />
<figcaption>A single video feed powers this example that recreates the feeling of a <a href="https://codepen.io/danwilson/pen/OdOWOp">digital Photo Booth with effects</a></figcaption>
</figure>
<p>We can get as creative as we want by not just taking video at face value but thinking about it as an input to be combined with everything else that HTML, CSS, and JavaScript give us. People have combined JavaScript with video to create <a href="https://theremin.app/">virtual Theremins</a> and <a href="https://codepen.io/jakealbaugh/full/ZxLKvG/">color-based music makers</a>. CSS and Canvas open the doors to manipulating the appearance of the video through filters, blend modes, clip paths, and more.</p>
<div class="demo-section">
<h4>Demo</h4>
<button type="button" id="blur-video">Blur</button>
<button type="button" id="flip-video">Flip</button>
<button type="button" id="clip-video">Clip Path (animated)</button>
</div>
<h3 id="getting-more-specific-with-a-device's-capabilities-and-constraints" tabindex="-1">Getting more specific with a device’s capabilities and constraints <a class="direct-link" href="https://danielcwilson.com/blog/2021/11/user-media/#getting-more-specific-with-a-device's-capabilities-and-constraints" aria-hidden="true">#</a></h3>
<p>Feature detection is always key with accessing video, as not every device/browser/camera will have the same capabilities. There are many different combinations that drive the feature set of your specific video stream we are requesting, and sometimes we will want our video stream to meet specific criteria to be useful.</p>
<p>In our earlier example, we asked if we have access to any video stream by passing <code>{ video: true }</code> into the <code>getUserMedia()</code> method. This object we pass in represents our <em>Constraints</em>. With <code>{ video: true }</code> we are telling the system to get us effectively any video stream, so this is the loosest constraint we can provide. There will be a default camera with default settings, and that is what we get.</p>
<p>However, we can start making more specific requests. As the developer, if I’d prefer to load a user-facing (selfie) camera, I can tell the API in my constraints object.</p>
<pre class="language-js"><code class="language-js">navigator<span class="token punctuation">.</span>mediaDevices<span class="token punctuation">.</span><span class="token function">getUserMedia</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br /> <span class="token literal-property property">video</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">facingMode</span><span class="token operator">:</span> <span class="token string">"user"</span> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>Alternatively, I could also prefer a camera on the back side of a device, where I could set <code>{ facingMode: "environment" }</code>. The key is that so far these are all preferences. If I request this back camera, but I am on a laptop that only has a front facing camera, then the API will play nice and still give me a video stream from the best available camera.</p>
<p>Other common constraints that can be available are <code>frameRate</code>, <code>aspectRatio</code>, and <code>height</code>/<code>width</code>.</p>
<div class="demo-section">
<h4>Demo</h4>
<label>Attempt to set the frame rate (frames per second)</label>
<select id="framerate">
<option value="">Select...</option>
<option value="2">2</option>
<option value="5">5</option>
<option value="10">10</option>
<option value="30">30</option>
<option value="60">43</option>
<option value="60">120</option>
</select>
<p id="fr-currently"></p>
</div>
<p>When we need to apply more restrictions, we can tell the API that we need specific values, by setting ranges or requesting an exact match.</p>
<pre class="language-js"><code class="language-js">navigator<span class="token punctuation">.</span>mediaDevices<span class="token punctuation">.</span><span class="token function">getUserMedia</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br /> <span class="token literal-property property">video</span><span class="token operator">:</span> <span class="token punctuation">{</span><br /> <span class="token literal-property property">facingMode</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">exact</span><span class="token operator">:</span> <span class="token string">"environment"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">aspectRatio</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">min</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token literal-property property">max</span><span class="token operator">:</span> <span class="token number">1.7777777778</span> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>These example constraints will require a camera that faces away from the user and has a stream that is least a square size and no more than a 16:9 ratio. If there is no camera that can support these requirements, no camera is returned and the <code>getUserMedia</code> Promise is rejected with a <code>MediaStreamError</code>.</p>
<h3 id="responsible-usage" tabindex="-1">Responsible usage <a class="direct-link" href="https://danielcwilson.com/blog/2021/11/user-media/#responsible-usage" aria-hidden="true">#</a></h3>
<p>As makers of the web, we have a responsibility to use these abilities well. We need to be clear and honest up front with how these inputs are used by us and what we build, and we need to empower the user to opt out at any point.</p>
<p>Once a video stream is loaded and playing, we no longer can set our constraints for the video via <code>getUserMedia()</code>. We need to store the video stream and adjust an individual video track within it.</p>
<p>In our starting example, we have a variable named <code>stream</code> that stores the stream (and its corresponding video track) resolved by the <code>getUserMedia()</code> Promise. We can act on this individual track at any point — such as stopping the video stream on a button press.</p>
<pre class="language-js"><code class="language-js">stopButton<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token parameter">e</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token comment">// We requested one video and no audio, so there is only one active track</span><br /> <span class="token keyword">const</span> track <span class="token operator">=</span> stream<span class="token punctuation">.</span><span class="token function">getTracks</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br /> track<span class="token punctuation">.</span><span class="token function">stop</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>This turns the camera off (as you can see if your device has a light indicator for the camera), but the video element might remain on the last captured screen. To assure the user camera access has stopped, we should also set the <code>video.srcObject = null</code> and remove the stream from our visible video element.</p>
<div class="demo-section">
<h4>Demo</h4>
<button type="button" id="stop-video">Stop</button>
<button type="button" id="restart-video">Restart</button>
</div>
<p>To see the constraints (as we currently requested them) on a given track we can call <code>track.getConstraints()</code> and we will see an object that matches the one we passed in to <code>getUserMedia</code>.</p>
<p>To see what <em>Settings</em> actually were applied (that is, which of our preferences became real), we can check <code>track.getSettings()</code>.</p>
<p>If we want to have better info around what other <em>Capabilities</em> are available to our active stream, we can see the ranges and possible values via <code>track.getCapabilities()</code>. However, this is one of the few pieces that is not in every major browser yet as it is not in Firefox as of this writing.</p>
<div class="demo-section">
<h4>Demo</h4>
<details>
<summary>getConstraints()</summary>
<pre><code id="current-constraints">Unknown</code></pre>
</details>
<details>
<summary>getCapabilities()</summary>
<pre><code id="current-capabilities">Unknown</code></pre>
</details>
<details>
<summary>getSettings()</summary>
<pre><code id="current-settings">Unknown</code></pre>
</details>
</div>
<p>Finally, to apply new constraints we can pass in a new constraints object to <code>track.applyConstraints()</code>. This is a full overwrite, so if we previously had specified a <code>aspectRatio</code> and on this new update we only set a <code>frameRate</code>, the old value for the <code>aspectRatio</code> will be forgotten and its default value will be in effect.</p>
<p>Our constraints object can even pass in a specific <code>deviceId</code> if we know how the system refers to a specific camera. Realistically we will not be able to know that in most cases ahead of time, but there is another Media Devices API we can use called <code>enumerateDevices</code>. Calling this will give us a list of all devices available, with the default ones listed first. This method, however, does not require user permission first, and if you call this method before allowing access via <code>getUserMedia</code> you will get a subset of available information.</p>
<pre class="language-js"><code class="language-js"><span class="token punctuation">[</span><span class="token punctuation">{</span><br /> <span class="token string-property property">"deviceId"</span><span class="token operator">:</span> <span class="token string">"abc"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"kind"</span><span class="token operator">:</span> <span class="token string">"videoinput"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"label"</span><span class="token operator">:</span> <span class="token string">""</span><span class="token punctuation">,</span> <span class="token comment">// This will be blank until user has granted camera permission</span><br /> <span class="token string-property property">"groupId"</span><span class="token operator">:</span> <span class="token string">"xyz"</span><br /><span class="token punctuation">}</span><span class="token punctuation">]</span></code></pre>
<p>If called after camera access is allowed, we get a slightly different result where the label is filled in.</p>
<pre class="language-js"><code class="language-js"><span class="token punctuation">[</span><span class="token punctuation">{</span><br /> <span class="token string-property property">"deviceId"</span><span class="token operator">:</span> <span class="token string">"abc"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"kind"</span><span class="token operator">:</span> <span class="token string">"videoinput"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"label"</span><span class="token operator">:</span> <span class="token string">"Front Camera"</span><span class="token punctuation">,</span><br /> <span class="token string-property property">"groupId"</span><span class="token operator">:</span> <span class="token string">"xyz"</span><br /><span class="token punctuation">}</span><span class="token punctuation">]</span></code></pre>
<p>With this information, it’s possible to have a button or dropdown that allows you to switch between cameras and change video streams by passing in the appropriate <code>deviceId</code> in as a constraint.</p>
<pre class="language-js"><code class="language-js">stream <span class="token operator">=</span> <span class="token keyword">await</span> navigator<span class="token punctuation">.</span>mediaDevices<span class="token punctuation">.</span><span class="token function">getUserMedia</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br /> <span class="token literal-property property">video</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token literal-property property">deviceId</span><span class="token operator">:</span> <span class="token string">"abc"</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">audio</span><span class="token operator">:</span> <span class="token boolean">false</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<div class="demo-section">
<h4>Demo</h4>
<label>Change camera if available</label>
<select id="change-device">
<option value="">Select...</option>
</select>
</div>
<h3 id="the-browser-still-provides-control" tabindex="-1">The browser still provides control <a class="direct-link" href="https://danielcwilson.com/blog/2021/11/user-media/#the-browser-still-provides-control" aria-hidden="true">#</a></h3>
<p>Now that we have been responsible and provided many options for our users to opt out or limit their camera usage, we must acknowledge that browsers also provide a lot of options to the user. Just as browsers have introduced ways to mute tabs playing audio in the background, they also (to varying levels) give users control over their camera and microphone usage. Ways to revoke access for all permissions-based methods (such as cameras and location services) have become prominent. So we always need to account for the fact that a user can remove access at any point.</p>
<p>Some browsers let you pause and play an active stream’s track without revoking access, and some even allow you to change the active camera.</p>
<figure>
<img src="https://danielcwilson.com/img/posts/2021/chromium.png" />
<figcaption>Options available to Chromium browser users with an active video.</figcaption>
</figure>
<h3 id="get-creative" tabindex="-1">Get creative <a class="direct-link" href="https://danielcwilson.com/blog/2021/11/user-media/#get-creative" aria-hidden="true">#</a></h3>
<p>Have fun, be creative, and empower users to be creative and in control.</p>
<div class="video-container">
<video playsinline="" muted="" autoplay=""></video>
<button type="button" id="revoke-access-2" class="revoker">Remove access</button>
</div>
<script>
let stream;
let videoInputs;
const video = document.querySelector('video');
const allowers = document.querySelectorAll('.allower');
const revokers = document.querySelectorAll('.revoker');
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
document.documentElement.classList.add('user-media-supported')
allowers.forEach(allower => {
allower.addEventListener('click', e => {
navigator.mediaDevices.getUserMedia({
video: true,
audio: false
}).then(s => {
stream = s;
video.srcObject = stream;
video.onloadedmetadata = () => {
video.play();
}
document.documentElement.classList.add('user-media-access');
updateSettings();
if (navigator.mediaDevices && navigator.mediaDevices.enumerateDevices) {
navigator.mediaDevices.enumerateDevices().then(devices => {
videoInputs = devices.filter((d) => d.kind.includes("video"));
const dropdown = document.getElementById("change-device");
dropdown.innerHTML = `<option value="">Select</option>`;
videoInputs.forEach((v) => {
const option = document.createElement("option");
option.textContent = v.label;
option.value = v.deviceId;
dropdown.appendChild(option);
});
});
}
}).catch(err => {
document.documentElement.classList.remove('user-media-access');
});
});
});
revokers.forEach(revoker => {
revoker.addEventListener('click', e => {
if (stream.getTracks()[0]) {
stream.getTracks()[0].stop();
video.srcObject = null;
document.documentElement.classList.remove('user-media-access');
}
});
});
document.getElementById('blur-video').addEventListener('click', e => {
video.animate([{filter: 'blur(10px)'},{filter: 'blur(10px)'}], {
duration: 2500
})
});
document.getElementById('clip-video').addEventListener('click', e => {
video.animate([{clipPath: 'circle(0 at 20% 50%)', offset:0},{clipPath: 'circle(35% at 20% 50%)', offset:0.1},{clipPath: 'circle(35% at 80% 50%)', offset:0.75},{clipPath: 'circle(100% at 50% 50%)', offset:1}], {
duration: 2500
})
});
document.getElementById('flip-video').addEventListener('click', e => {
video.animate([{transform: 'scaleX(-1)'},{transform: 'scaleX(-1)'}], {
duration: 2500
})
});
document.getElementById('framerate').addEventListener('change', e => {
if (stream.getTracks()[0] && e.currentTarget.value.length > 0) {
stream.getTracks()[0].applyConstraints({
frameRate: e.currentTarget.value
}).then( r => {
const settings = stream.getTracks()[0].getSettings();
const rate = settings && settings.frameRate;
if (rate > -1) {
document.getElementById('fr-currently').textContent = `Currently: ${Math.round(rate)} frames per second`;
updateSettings();
}
});
}
});
document.getElementById('stop-video').addEventListener('click', e => {
if (stream.getTracks()[0]) {
stream.getTracks()[0].stop();
video.srcObject = null;
document.getElementById('fr-currently').textContent = "";
document.getElementById('framerate').value = "";
document.getElementById('change-device').value = "";
//document.getElementById('change-device').setAttribute("disabled", "disabled");
clearSettings();
}
});
document.getElementById('restart-video').addEventListener('click', e => {
if (stream.getTracks()[0]) {
navigator.mediaDevices.getUserMedia({
video: true,
audio: false
}).then(s => {
stream = s;
video.srcObject = stream;
video.onloadedmetadata = () => {
video.play();
}
document.documentElement.classList.add('user-media-access');
updateSettings();
//document.getElementById('change-device').removeAttribute("disabled");
});
}
});
document.getElementById('change-device').addEventListener("change", (e) => {
if (stream.getTracks()[0]) {
navigator.mediaDevices.getUserMedia({
video: {
deviceId: e.currentTarget.value
},
audio: false
}).then(s => {
stream = s;
video.srcObject = stream;
video.onloadedmetadata = () => {
video.play();
}
document.documentElement.classList.add('user-media-access');
document.getElementById('fr-currently').textContent = "";
document.getElementById('framerate').value = "";
updateSettings();
//document.getElementById('change-device').removeAttribute("disabled");
});
}
});
function updateSettings() {
const track = stream.getTracks()[0];
if (track && track.getConstraints) {
document.getElementById('current-constraints').textContent = JSON.stringify(track.getConstraints(), null, 2);
}
if (track && track.getCapabilities) {
document.getElementById('current-capabilities').textContent = JSON.stringify(track.getCapabilities(), null, 2);
}
if (track && track.getSettings) {
document.getElementById('current-settings').textContent = JSON.stringify(track.getSettings(), null, 2);
}
}
function clearSettings() {
document.getElementById('current-constraints').textContent = "Unknown"
document.getElementById('current-capabilities').textContent = "Unknown"
document.getElementById('current-settings').textContent = "Unknown"
}
}
</script>
Additive Animations in CSS2020-10-03T11:48:30Zhttps://danielcwilson.com/blog/2020/10/additive-css-animations/<p class="preamble">The following is supported in the latest Safari, Firefox, Edge, and Chrome.</p>
<p>What happens when you have two simultaneous animations in CSS that modify the same property?</p>
<pre class="language-css"><code class="language-css"><span class="token selector">div</span> <span class="token punctuation">{</span><br /> <span class="token property">animation</span><span class="token punctuation">:</span><br /> x 2000ms infinite alternate ease-in<span class="token punctuation">,</span><br /> y 2000ms infinite alternate ease-out<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token atrule"><span class="token rule">@keyframes</span> x</span> <span class="token punctuation">{</span><br /> <span class="token selector">from</span> <span class="token punctuation">{</span> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateX</span><span class="token punctuation">(</span>0vw<span class="token punctuation">)</span> <span class="token punctuation">}</span><br /> <span class="token selector">to</span> <span class="token punctuation">{</span> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateX</span><span class="token punctuation">(</span>90vw<span class="token punctuation">)</span> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><span class="token atrule"><span class="token rule">@keyframes</span> y</span> <span class="token punctuation">{</span><br /> <span class="token selector">from</span> <span class="token punctuation">{</span> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateY</span><span class="token punctuation">(</span>0vh<span class="token punctuation">)</span> <span class="token punctuation">}</span><br /> <span class="token selector">to</span> <span class="token punctuation">{</span> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateY</span><span class="token punctuation">(</span>90vh<span class="token punctuation">)</span> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p><a href="https://codepen.io/danwilson/pen/vYGogpP">View Demo</a></p>
<p>Only one <code>transform</code> value can be set at a given time, so only one of the translations will occur (the last one in the <code>animation</code> list wins, so for this example it is the vertical animation with <code>translateY()</code>).</p>
<p>The Web Animations API allows us to mix up this behavior through the introduction of the <code>composite</code> option.</p>
<h3 id="additive-animation" tabindex="-1">Additive Animation <a class="direct-link" href="https://danielcwilson.com/blog/2020/10/additive-css-animations/#additive-animation" aria-hidden="true">#</a></h3>
<p>First, we can make an equivalent animation in the WAAPI as the previous CSS example:</p>
<pre class="language-js"><code class="language-js">element<span class="token punctuation">.</span><span class="token function">animate</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br /> <span class="token literal-property property">transform</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'translateX(0vw)'</span><span class="token punctuation">,</span><span class="token string">'translateX(90vw)'</span><span class="token punctuation">]</span><br /><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br /> <span class="token literal-property property">duration</span><span class="token operator">:</span> <span class="token number">2000</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">easing</span><span class="token operator">:</span> <span class="token string">'ease-in'</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">iterations</span><span class="token operator">:</span> <span class="token number">Infinity</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">direction</span><span class="token operator">:</span> <span class="token string">'alternate'</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />element<span class="token punctuation">.</span><span class="token function">animate</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br /> <span class="token literal-property property">transform</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'translateY(0vh)'</span><span class="token punctuation">,</span><span class="token string">'translateY(90vh)'</span><span class="token punctuation">]</span><br /><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br /> <span class="token literal-property property">duration</span><span class="token operator">:</span> <span class="token number">2000</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">easing</span><span class="token operator">:</span> <span class="token string">'ease-in'</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">iterations</span><span class="token operator">:</span> <span class="token number">Infinity</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">direction</span><span class="token operator">:</span> <span class="token string">'alternate'</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>The default behavior remains the same, so this code will do the exact same as the CSS, where only the vertical translation will occur.</p>
<p>It does let us start playing with a new option, however, called the <code>composite</code> property. Its default value is <code>'replace'</code> which is the behavior we have discussed so far, where a value on a property is replaced by a newer animation that comes along and tries to modify the same property.</p>
<p>If we change the second animation to add a <code>composite: 'add'</code> option, we tell it to add the value of this animation to whatever the current state of that property is.</p>
<pre class="language-js"><code class="language-js">element<span class="token punctuation">.</span><span class="token function">animate</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br /> <span class="token literal-property property">transform</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'translateY(0vh)'</span><span class="token punctuation">,</span><span class="token string">'translateY(90vh)'</span><span class="token punctuation">]</span><br /><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br /> <span class="token literal-property property">duration</span><span class="token operator">:</span> <span class="token number">2000</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">easing</span><span class="token operator">:</span> <span class="token string">'ease-in'</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">iterations</span><span class="token operator">:</span> <span class="token number">Infinity</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">direction</span><span class="token operator">:</span> <span class="token string">'alternate'</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">composite</span><span class="token operator">:</span> <span class="token string">'add'</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Now, instead of replacing the value defined by the first animation, it adds our new value. For <code>transform</code> which has a syntax that accepts a list of transform functions, adding means appending the new transform functions to the end of the existing list. The <code>filter</code> property is another list-based property that will allow you to keep appending new values to the list of functions.</p>
<p class="codepen" data-height="265" data-theme-id="default" data-default-tab="js,result" data-user="danwilson" data-slug-hash="NWNQdXx" data-preview="true" data-editable="true" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Transform with composite add">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/NWNQdXx">
Transform with composite add</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>For properties that are not lists, add behaves slightly differently, but in line with what you may expect. Properties that accept any number-based valu (such as lengths, percentages, or raw numbers) will add the numbers together. So if you have two animations affecting <code>opacity</code>, the resulting visual opacity will be the sum of the current values of <code>opacity</code> in each animation.</p>
<p class="codepen" data-height="347" data-theme-id="default" data-default-tab="js,result" data-user="danwilson" data-slug-hash="bGpONjp" style="height: 347px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Opacity Animations with `composite: 'add'`">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/bGpONjp">
Opacity Animations with `composite: 'add'`</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>The same goes for moving an item 20px + 30px with margin left (not the most performant way to move an object, but it demonstrates length usage)... if the animations both run at the same time, with the same duration and in the same direction, the <a href="https://codepen.io/danwilson/pen/QWNoJOr">end result will be a movement of 50px</a>.</p>
<h3 id="bringing-it-to-css" tabindex="-1">Bringing it to CSS <a class="direct-link" href="https://danielcwilson.com/blog/2020/10/additive-css-animations/#bringing-it-to-css" aria-hidden="true">#</a></h3>
<p>Currently, there is no way to specify this same behavior in CSS, though there have been <a href="https://github.com/w3c/csswg-drafts/issues/1594">discussions to add it</a>. That doesn’t mean our CSS animations cannot take advantage of this option today.</p>
<p>With the <code>getAnimations()</code> method on elements (including the <code>document</code>) you can fetch all the WAAPI animations, CSS animations, and CSS transitions that are active on the element. More importantly, we can modify the keyframes, timing options, or <code>composite</code> property on any animation returned. So all of a sudden our animations (even our CSS ones) can be updated at any time (even while they are running).</p>
<p>All that to say... you can use the magic of <code>composite</code> on CSS animations and transitions by adding a little bit of JavaScript:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> animated <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'my-element'</span><span class="token punctuation">)</span><br />animated<span class="token punctuation">.</span><span class="token function">getAnimations</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">animation</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> animation<span class="token punctuation">.</span>effect<span class="token punctuation">.</span>composite <span class="token operator">=</span> <span class="token string">'add'</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p class="codepen" data-height="328" data-theme-id="default" data-default-tab="css,result" data-preview="true" data-user="danwilson" data-slug-hash="poyQgPP" style="height: 328px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Additive CSS Animations">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/poyQgPP">
Additive CSS Animations</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>Once you have an element, you can call <code>getAnimations()</code> on it, iterate through the array of animations, and update each one to update the <code>composite</code> property. If you need to only add it to certain animations in the list, you can check the <code>animation.animationName</code> property for CSS Animations or <a href="https://danielcwilson.com/blog/2020/04/css-in-the-waapi/">use other methods to determine which animation is which</a>.</p>
<p>This can also go along with the <code>animationstart</code> and other events to make sure you are updating the property at an appropriate time. These events do not contain an <code>Animation</code> object in the handler, but they do return identifying information such as the <code>animationName</code>. So we can cross reference this <code>event.animationName</code> with the <code>animationName</code> found in the <code>getAnimations()</code> list for CSS Animations to pinpoint and update any animation we are looking for.</p>
<pre class="language-js"><code class="language-js">animated<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'animationstart'</span><span class="token punctuation">,</span> <span class="token parameter">e</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">const</span> all <span class="token operator">=</span> animated<span class="token punctuation">.</span><span class="token function">getAnimations</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">const</span> myAnimation <span class="token operator">=</span> all<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token parameter">anim</span> <span class="token operator">=></span> anim<span class="token punctuation">.</span>animationName <span class="token operator">===</span> e<span class="token punctuation">.</span>animationName<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> myAnimation<span class="token punctuation">.</span>effect<span class="token punctuation">.</span>composite <span class="token operator">=</span> <span class="token string">'add'</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
Pseudo-elements in the Web Animations API2020-05-04T11:48:30Zhttps://danielcwilson.com/blog/2020/05/pseudo-waapi/<p class="preamble">As of September 2020, the features discussed are now in the latest versions of Firefox, Safari, Edge, and Chrome.</p>
<p>One of the few pieces that was readily available to CSS but not to the Web Animations API was animating pseudo-elements (such as <code>::before</code> and <code>::after</code>). However, this is starting to be supported in the latest rollout of Web Animations API functionality.</p>
<p>When you use the Web Animations API, you start by getting a reference to an element where you can apply an animation. This will be the original element by default.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> logo <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'logo'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">const</span> main <span class="token operator">=</span> logo<span class="token punctuation">.</span><span class="token function">animate</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">opacity</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br /> <span class="token literal-property property">duration</span><span class="token operator">:</span> <span class="token number">100</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>The second parameter takes our timing options and a few other options (like an <code>id</code> and <code>composite</code>). This is where we can specify that we don’t want this animation applied to the main element, but instead a pseudo-element.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> logo <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'logo'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">const</span> secondary <span class="token operator">=</span> logo<span class="token punctuation">.</span><span class="token function">animate</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">opacity</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br /> <span class="token literal-property property">duration</span><span class="token operator">:</span> <span class="token number">100</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">pseudoElement</span><span class="token operator">:</span> <span class="token string">'::after'</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Expected Result:</p>
<video muted="" playsinline="" loop="" controls="">
<source src="https://danielcwilson.com/img/posts/2020/pseudo-waapi.mp4" />
</video>
<p>Live Result:</p>
<p class="codepen" data-height="265" data-theme-id="dark" data-default-tab="js,result" data-user="danwilson" data-slug-hash="oNjwyOV" data-preview="true" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="WAAPI pseudoElement">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/oNjwyOV">
WAAPI pseudoElement</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>By observation, it appears that Firefox supports <code>::after</code>, <code>::before</code>, and <code>::marker</code>. Others (such as <code>::first-letter</code> or <code>::selection</code>) are not supported. If the browser supports usage of <code>pseudoElement</code>, but the specified pseudo-element is not valid or not supported, an error will be thrown and no animation will happen.</p>
<p>If you have a reference to an animation, you can check if it is running on a pseudo-element by checking inside the <code>effect</code> property. Using the animations from the previous examples:</p>
<pre class="language-js"><code class="language-js">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>main<span class="token punctuation">.</span>effect<span class="token punctuation">.</span>pseudoElement<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// null</span><br /><br />console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>secondary<span class="token punctuation">.</span>effect<span class="token punctuation">.</span>pseudoElement<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">// "::after"</span></code></pre>
CSS + the Web Animations API2020-04-16T03:48:30Zhttps://danielcwilson.com/blog/2020/04/css-in-the-waapi/<p class="preamble">As of 2022, everything discussed in this article is supported across the latest versions of Safari, Firefox, Edge, and Chrome.</p>
<p>While the Web Animations API initially brought a similar mechanism as CSS animations to JavaScript, it also added a few additional features like modifying playback rate and jumping to different points in an animation’s timeline. As the final pieces of the Web Animations Level 1 specification roll out to browsers, it’s not just JavaScript that gets extra features.</p>
<h3 id="getting-all-web-animations-with-the-api" tabindex="-1">Getting all Web Animations with the API <a class="direct-link" href="https://danielcwilson.com/blog/2020/04/css-in-the-waapi/#getting-all-web-animations-with-the-api" aria-hidden="true">#</a></h3>
<p>One of the newer pieces now available is the ability to get references to all the animations for a specific element or even a full document. A reference to an animation is key to be able to update the animation later or set listeners for events.</p>
<pre class="language-js"><code class="language-js"><span class="token comment">//returns an array of all active animations contained within the document</span><br />document<span class="token punctuation">.</span><span class="token function">getAnimations</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token comment">//returns an array of all active animations for a specific element</span><br />document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'header'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getAnimations</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br /><br /><span class="token comment">//returns an array of all active animations for a specific element and its descendants</span><br />document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'header'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getAnimations</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">subtree</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>When called on the document, every active animation on your page will be returned.</p>
<p>When called on an element, by default you will get all the active animations on that specific element. You can also specify an options object parameter with the property <code>subtree</code> enabled if you want to see all the animations for a given element <em>and</em> every element it contains as a descendant.</p>
<p>The best part is that this new Web Animations API method does not just return animations that were created with the Web Animations API, but also CSS Animations and CSS Transitions. Any API method can then be called on the CSS animations and transitions as though it had been created by the API.</p>
<h3 id="how-do-i-know-where-an-animation-was-created" tabindex="-1">How do I know where an animation was created? <a class="direct-link" href="https://danielcwilson.com/blog/2020/04/css-in-the-waapi/#how-do-i-know-where-an-animation-was-created" aria-hidden="true">#</a></h3>
<p>Each animation that appears in the <code>getAnimations()</code> array today will be of type <code>Animation</code>, <code>CSSAnimation</code>, or <code>CSSTransition</code>. The two CSS ones extend the <code>Animation</code> interface.</p>
<p>This means each type will have the normal Web Animations API methods, but the two CSS ones will have an extra property that are specific to those needs.</p>
<p class="codepen" data-height="342" data-theme-id="dark" data-default-tab="css,result" data-user="danwilson" data-slug-hash="bGVNzJr" data-preview="true" style="height: 342px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="WAAPI: Check if an Animation is from the WAAPI">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/bGVNzJr">
WAAPI: Check if an Animation is from the WAAPI</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p><a href="https://drafts.csswg.org/css-animations-2/#the-CSSAnimation-interface">CSS Animations</a> will have a property called <code>animationName</code> that will expose the animation name (the same that appears in the CSS <code>animation-name</code> and the <code>@keyframes</code> definition). <a href="https://drafts.csswg.org/css-transitions-2/#the-CSSTransition-interface">CSS Transitions</a> will similarly have <code>transitionProperty</code> to share which property it is responsible for transitioning.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> animations <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getAnimations</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token comment">// Iterate through each animation to inspect</span><br />animations<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">animation</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">if</span> <span class="token punctuation">(</span>animation<span class="token punctuation">.</span>animationName<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token comment">// CSS Animation with the specified name</span><br /> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>animation<span class="token punctuation">.</span>transitionProperty<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token comment">// CSS Transition on the specified property</span><br /> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br /> <span class="token comment">// Web Animations API</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>That leaves all the rest as ones from the Web Animations API (though, SVG Animations are mentioned in the specification as also making it in here one day). If you need to know which WAAPI animation is which, you can look at the keyframes or timing options, or specify an <code>id</code> at creation which is returned back.</p>
<h3 id="extending-css-animations-with-the-web-animations-api" tabindex="-1">Extending CSS Animations with the Web Animations API <a class="direct-link" href="https://danielcwilson.com/blog/2020/04/css-in-the-waapi/#extending-css-animations-with-the-web-animations-api" aria-hidden="true">#</a></h3>
<p>Since all these animations share a common interface and have the same underlying engine behind them (one of the main goals of the Web Animations <a href="https://drafts.csswg.org/web-animations-1/#relationship-to-other-specifications">specification</a>), we can now use the API to interact with our CSS animations.</p>
<p class="codepen" data-height="342" data-theme-id="dark" data-default-tab="css,result" data-user="danwilson" data-slug-hash="qGdJGq" style="height: 342px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="HyperCSS">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/qGdJGq">
HyperCSS</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>For browsers that do not support <code>getAnimations()</code>, a simple button that allows the user to start or pause a CSS animation appears. However, with the ability to grab these animations from the API in supported browsers, a range slider is swapped in that allows the user to vary the playback rate of the CSS animations. This happens because the API has the <code>updatePlaybackRate()</code> that allows us to speed up or slow down an animation, and our CSS Animations can now leverage this feature (there is a <a href="https://bugs.webkit.org/show_bug.cgi?id=188841">known bug in Webkit</a>, however, so playback rate in Safari does not update as of this writing). We can also jump to (or read) specific points in our animation timeline through the <code>currentTime</code> read/write property, and we can read or update the specific keyframes or timing options (such as duration, delay, and iterations).</p>
<p>There are also more direct ways to cancel or finish an animation. With CSS animations, you could always update the <code>style.animationName = 'none'</code> in JavaScript, but now you can also call <code>cancel()</code> on the animation. CSS animations and transitions have long had solid JavaScript event listeners for <code>animationend</code>, <code>transitionstart</code>, and others, so the Web Animations API does not bring much new here. That said, the WAAPI offers comparable callbacks and Promises if those are preferred.</p>
<p>And if you want to get a sneak preview of the next ways that the API will be extending capabilities, check out Firefox Nightly to see <a href="https://css-tricks.com/additive-animation-web-animations-api/">additive animation</a> in action.</p>
When 255 × 0 does not Equal Zero2020-03-03T22:59:30Zhttps://danielcwilson.com/blog/2020/03/blend-modes-in-spaaaace/<p>First, a caveat: I am not an expert in color management and monitor display profiles. I also only understand the surface-level differences between the default color space of sRGB on the web and other newer models. This conversation will include discussions of both, and I’ll explain what I know and leave room (and links) for others to chime in with better explanations.</p>
<p>Okay… now with that out of the way (and I guess… sorry for the early spoiler of what the article is going to address): Let’s talk the mathematics of blend modes!</p>
<h3 id="how-blend-modes-work-on-the-web-today" tabindex="-1">How blend modes work on the web today <a class="direct-link" href="https://danielcwilson.com/blog/2020/03/blend-modes-in-spaaaace/#how-blend-modes-work-on-the-web-today" aria-hidden="true">#</a></h3>
<p>If you have used Photoshop (or bonus points for fellow Corel-Photo-Paint-in-the-1990s fans) or dealt with <code>mix-blend-mode</code> or <code>background-blend-mode</code> in CSS, you might be somewhat familiar with blend modes. When two layers or elements overlap while a blend mode is specified, a computation will occur at each pixel using the two elements’ RGB color values as inputs, resulting in a new color to display. There are many different modes like <code>multiply</code> and <code>hard-light</code> that each perform a different formula where elements overlap to visually present a different color.</p>
<p>Most of the time, I suspect, designers scroll through different modes to see what looks the best to them, perhaps additionally adding an opacity to the elements to soften the effects. But since every mode has a specific formula, it is entirely possible to understand the resulting color just by looking at your two source colors.</p>
<p>The web follows sRGB for its default color space. This happens for <a href="https://danielcwilson.com/blog/2019/09/huedini">interpolating colors in animations and gradients</a>, and it makes the math fairly straightforward. Even if you specify a value in HSL (with hue, saturation, and lightness), the resulting color will be computed as a RGB color (red, green, and blue). More options are coming in the CSS Colors <a href="https://drafts.csswg.org/css-color-4/">Level 4</a> and <a href="https://drafts.csswg.org/css-color-5/">Level 5</a> specifications, and there is plenty of talk on the working group Github about how the future might allow us to <a href="https://github.com/w3c/csswg-drafts/issues/4647">interpolate along different models</a>.</p>
<p>But as of today, blend mode math happens once for the red channel, once for green, and once for blue.</p>
<p>We will focus on <code>multiply</code> for our example of this math, and then we will will talk about some key issues where the math doesn’t add up.</p>
<h3 id="the-multiply-blend-mode" tabindex="-1">The <code>multiply</code> blend mode <a class="direct-link" href="https://danielcwilson.com/blog/2020/03/blend-modes-in-spaaaace/#the-multiply-blend-mode" aria-hidden="true">#</a></h3>
<p>Let’s take the color <code>red</code> defined as <code>#ff0000</code>. Each channel is a number between 0 and 255 (inclusive). This color has 255 in the red channel and 0 in the green and blue.</p>
<p><code>#ff0000</code> is equivalent to the function value of <code>rgb(255,0,0)</code>. You can also use percentages in this function, so for the rest of the article we will be talking values of <code>0%</code> to <code>100%</code> instead of 0 to 255. With this notation, red is <code>rgb(100%, 0%, 0%)</code>.</p>
<p>Let’s say we want to blend this with another color, and let’s choose yellow as <code>rgb(100%,100%,0%)</code></p>
<p>To perform a <code>multiply</code> blend mode we take the values of each element along each channel and multiply them. We do this in a 0 - 1 scale though (so <code>100%</code> is <code>1</code> and <code>50%</code> is <code>.5</code>, etc.)</p>
<ul>
<li>Red in RGB: <code>rgb(100%, 0%, 0%)</code></li>
<li>Yellow in RGB: <code>rgb(100%, 100%, 0%)</code></li>
<li>Multiplication in R channel: <code>1 × 1 = 1</code></li>
<li>Multiplication in G channel: <code>0 × 1 = 0</code></li>
<li>Multiplication in B channel: <code>0 × 0 = 0</code></li>
</ul>
<p>So our result, when converting back to percentages is <code>rgb(100%, 0%, 0%)</code>… otherwise known as our original red source value!</p>
<figure>
<img src="https://danielcwilson.com/img/posts/2020/blendRedYellow.png" />
<figcaption>Multiplying red and yellow results in red. View the <a href="https://codepen.io/danwilson/pen/MWwvoOe">live example on CodePen</a>.</figcaption>
</figure>
<p>What if we instead chose cyan (<code>rgb(0%,100%,100%)</code>)?</p>
<ul>
<li>Red in RGB: <code>rgb(100%, 0%, 0%)</code></li>
<li>Cyan in RGB: <code>rgb(0%, 100%, 100%)</code></li>
<li>Multiplication in R channel: <code>1 × 0 = 0</code></li>
<li>Multiplication in G channel: <code>0 × 1 = 0</code></li>
<li>Multiplication in B channel: <code>0 × 1 = 0</code></li>
</ul>
<p>Now, converting back to percentages, we get <code>rgb(0%, 0%, 0%)</code> : <code>black</code></p>
<figure>
<img src="https://danielcwilson.com/img/posts/2020/blendRedCyan.png" />
<figcaption>Multiplying red and cyan results in black. View the <a href="https://codepen.io/danwilson/pen/gOpxRvE">live example on CodePen</a>.</figcaption>
</figure>
<p>Since we are multiplying values less than or equal to one, our multiplication blend mode will never result in a color lighter than we started. Each channel will stay the same as one of the sources or be darker (approach zero).</p>
<p>To me, there is magic in values like red and cyan where the result is three zeroes… knowing how to get black from a multiply blend mode gives you a lot of power in controlling how your final design looks. And the math is fairly straightforward, so it’s reassuring in a world of uncertainty that two colors will always result in the same third color any time you blend them together.</p>
<p>Until they don’t.</p>
<h3 id="when-math-happens-outside-your-color-space" tabindex="-1">When math happens outside your color space <a class="direct-link" href="https://danielcwilson.com/blog/2020/03/blend-modes-in-spaaaace/#when-math-happens-outside-your-color-space" aria-hidden="true">#</a></h3>
<p>So there is a thing with color spaces. Color management is one of those topics I’ve known about for a quarter century but never dug into how it all really works. Everything is a lot simpler when red is red and green is green and you don’t think harder than that. But thankfully several people do think about these topics and as a result our displays have become more vibrant and consistent.</p>
<p>As noted earlier, when you specify a color such as <code>rgb(100% 0% 0%)</code> on the web you are dealing with sRGB color space, and it’s the primary color specification that the web knows. There are other newer ways to specify color, such as through the <code>color()</code> function, that are starting to be implemented, but basically if you want a bright red, you go <code>rgb(100% 0% 0%)</code>. When you say you want a gradient from that red to blue (<code>rgb(0% 0% 100%)</code>), the browser determines the in-between values in that same sRGB space and does the math by taking the red channel from 100 to 0 while simultaneously taking the blue channel from 0 to 100.</p>
<p>But different displays and monitors use different color spaces when they render out the color to the user. So, for example, on a Mac, you can open up your System Preferences > Displays > Color and find what display profile your computer uses. Chances are it uses something called Color LCD or iMac and ultimately what that means is when you specify <code>rgb(100% 0% 0%)</code> for red on the web in a browser that uses the device color management scheme (such as Safari or Edge/Chrome) the browser technically uses a different R/G/B value to give you a similar red.</p>
<p>On an iMac I used recently (with the help of the Digital Color Meter tool), the color that is produced at the display level is not <code>255 0 0</code> but instead <code>252 13 27</code></p>
<figure>
<img src="https://danielcwilson.com/img/posts/2020/redNative.png" />
<figcaption>Red uses slightly different values when in sRGB vs various display profiles.</figcaption>
</figure>
<p>Similarly my cyan (specified as <code>rgb(0 255 255)</code>) came back as <code>rgb(45 255 254)</code>.</p>
<figure>
<img src="https://danielcwilson.com/img/posts/2020/cyanNative.png" />
<figcaption>Cyan uses slightly different values when in sRGB vs various display profiles.</figcaption>
</figure>
<p>This isn’t information that most designers or developers need to deal with, since again interpolation on the web happens in sRGB so the math for our gradient earlier still happens between the original values. The display system does its own computation to take those sRGB colors determined by the browser to the appropriate display values.</p>
<p>Okay.</p>
<p>Now here’s the twist.</p>
<p>Math doesn’t always happen in sRGB.</p>
<p>Specifically… and you might have guessed it by now based on the amount of time I spent discussing blend modes…</p>
<p>Blend mode math in Safari, Edge, and Chrome happens in the <em>display’s color space</em> and <em>not</em> sRGB.</p>
<p>:Head exploding emoji:</p>
<h3 id="so...-what-does-that-mean" tabindex="-1">So... what does that mean? <a class="direct-link" href="https://danielcwilson.com/blog/2020/03/blend-modes-in-spaaaace/#so...-what-does-that-mean" aria-hidden="true">#</a></h3>
<p>It means, as of today, I can only consistently specify colors in sRGB and with blend modes I can only get a result specified by the display color profile. Converting our previously discussed Mac display values for red and cyan into percentages we get:</p>
<ul>
<li>Red: <code>rgb(98.824% 5.098% 10.588%)</code></li>
<li>Cyan: <code>rgb(17.647% 100% 99.608%)</code></li>
</ul>
<p>And when Chrome or Safari performs multiplication blend mode with those values (that originally gave us <code>rgb(0 0 0)</code> in sRGB):</p>
<ul>
<li>Multiplication in R channel: <code>.98824 × .17647 = 17.439%</code></li>
<li>Multiplication in G channel: <code>.05098 × 1 = 5.098%</code></li>
<li>Multiplication in B channel: <code>.10588 × .99608 = 10.546%</code></li>
</ul>
<p>Which is certainly a dark color… but it is not black. The two source colors defined in sRGB result in a color defined in sRGB using math in a different color space.</p>
<p>Similar combinations of colors that should equal black, such as yellow (<code>rgb(100% 100% 0%)</code>) times blue (<code>rgb(0% 0% 100%)</code>) also get values that are close to black... but not black.</p>
<figure>
<img src="https://danielcwilson.com/img/posts/2020/blendMac.png" />
<figcaption>Multiplication in different color spaces produce values that are not quite black. View the <a href="https://codepen.io/danwilson/pen/oNXBOPW">live example on CodePen</a>.</figcaption>
</figure>
<h3 id="is-this-expected" tabindex="-1">Is this expected? <a class="direct-link" href="https://danielcwilson.com/blog/2020/03/blend-modes-in-spaaaace/#is-this-expected" aria-hidden="true">#</a></h3>
<p>I would argue this is not the expected behavior. Throughout the color/values/animation specifications it discusses how interpolation and math with mixing colors is done in the same default color space as colors are defined (sRGB). In the <a href="https://www.w3.org/TR/compositing-1/">compositing spec</a>, the only discussion of color spaces is in the “Non-separable blend modes” section, where the blend modes around hue and saturation are discussed.</p>
<p>As mentioned earlier, in Firefox this is not an issue, though people say this is partly because Firefox does not support advanced color management.</p>
<p>Another reason this feels like the incorrect way to handle the math is that it is not consistent with Canvas blending. If you use the same colors in a <code>canvas</code> with the same blending, the result is solid <code>black</code> even in Safari and Chrome.</p>
<figure>
<img src="https://danielcwilson.com/img/posts/2020/blendCanvas.png" />
<figcaption>A red × cyan blend mode within a canvas in Chrome correctly renders solid black. View the <a href="https://codepen.io/danwilson/pen/MWwwdaM">live example on CodePen</a>.</figcaption>
</figure>
<p>But the biggest reason in my head is that if the only way we can really specify colors in one way with a fixed set of numbers… the math should respect those numbers we specify.</p>
<h3 id="the-larger-discussion" tabindex="-1">The larger discussion <a class="direct-link" href="https://danielcwilson.com/blog/2020/03/blend-modes-in-spaaaace/#the-larger-discussion" aria-hidden="true">#</a></h3>
<p>People who have a solid understanding of color management (in addition to colors on the web) are discussing ways to approach this in the future. <a href="https://twitter.com/svgeesus">Chris Lilley</a> and others at the W3C have pushed for color management on the web for a long time, and have discussed options to allow for <a href="https://github.com/w3c/csswg-drafts/issues/300">specifying the color space for a document</a>, etc (thanks to <a href="https://twitter.com/AmeliasBrain">Amelia Bellamy-Royds</a> for pointing me to several related Github issues on the topic). Even in these areas it seems the consensus should be that sRGB is the default for compatibility and especially when you are using that to begin with. In the future when we have the ability to use <code>lab()</code> or <code>color(display-p3 100% 0% 0%)</code> which give us a different range of colors in certain color spaces, we might be able to assume a different default for interpolation and compositing. It will be fun to see where the newer levels of the color specification go with people like Chris, <a href="https://twitter.com/leaverou">Lea Verou</a>, <a href="https://twitter.com/una">Una Kravets</a>, and <a href="https://twitter.com/argyleink/">Adam Argyle</a> as editors on the spec.</p>
<p>A big thank you to <a href="https://twitter.com/etportis">Eric Portis</a> for walking me through some of the Mac tooling (like the Digital Color Meter) and the basics of the monitor display profiles. That was integral to even start to understand why my visual results were not matching the math defined in the specification. He also started a <a href="https://twitter.com/etportis/status/1227307840701898753">small discussion on Twitter</a> which verified some of our theories as to what was happening with the blend modes.</p>
How They Fit Together: Transform, Translate, Rotate, Scale, and Offset2020-02-25T23:59:30Zhttps://danielcwilson.com/blog/2020/02/motion-path-transforms/<p>The <code>transform</code> property and its friends became more powerful through the addition of the new individual transform properties (<code>translate</code>, <code>rotate</code>, <code>scale</code>) and the <code>offset</code> properties (as a part of <a href="https://danielcwilson.com/blog/2020/01/motion-path-quirks/">CSS Motion Path</a>). All effectively provide a transformation for your element, and all have to follow specific rules to know how those transformations apply.</p>
<p>These new properties are now available in Firefox 72+. Motion path properties are also in Chromium browsers, and the independent transform properties are behind the Experimental Web Platform Features flag.</p>
<p>The power of the <code>transform</code> property is that it can hold <em>any number</em> of transformations. There can be multiple translations, rotations, scalings, skewings, and perspective changes. If you combine them in different orders, you can get different effects.</p>
<p>How do all these new properties interact with <code>transform</code> and <code>transform-origin</code>?</p>
<h3 id="basics-of-transformations" tabindex="-1">Basics of Transformations <a class="direct-link" href="https://danielcwilson.com/blog/2020/02/motion-path-transforms/#basics-of-transformations" aria-hidden="true">#</a></h3>
<p>When you perform transformations, you technically are not modifying the element itself. You are affecting its coordinate system. So a rotation rotates the x and y axes. If you have a transform that rotates 45 degrees and then apply a translate 100 pixels to the right, the translation will not go to the true right. It will instead go to the right of the already rotated coordinate system, so it will be going down and to the right at the 45 degree angle.</p>
<p class="codepen" data-height="324" data-theme-id="dark" data-default-tab="css,result" data-user="danwilson" data-slug-hash="eEYdgo" data-editable="true" style="height: 324px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Visual Reference: Transform Coordinate Systems">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/eEYdgo">
Visual Reference: Transform Coordinate Systems</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<h3 id="what-new-options-do-the-independent-transform-properties-provide" tabindex="-1">What new options do the independent transform properties provide? <a class="direct-link" href="https://danielcwilson.com/blog/2020/02/motion-path-transforms/#what-new-options-do-the-independent-transform-properties-provide" aria-hidden="true">#</a></h3>
<pre class="language-css"><code class="language-css"><span class="token selector">aside</span> <span class="token punctuation">{</span><br /> <span class="token property">rotate</span><span class="token punctuation">:</span> 33deg<span class="token punctuation">;</span><br /> <span class="token property">scale</span><span class="token punctuation">:</span> .85<span class="token punctuation">;</span><br /> <span class="token property">translate</span><span class="token punctuation">:</span> 20px 50px<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token selector">aside.equivalent</span> <span class="token punctuation">{</span><br /> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translate</span><span class="token punctuation">(</span>20px<span class="token punctuation">,</span> 50px<span class="token punctuation">)</span> <span class="token function">rotate</span><span class="token punctuation">(</span>33deg<span class="token punctuation">)</span> <span class="token function">scale</span><span class="token punctuation">(</span>.85<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>Instead of always having everything inside the <code>transform</code> function, we can specify one translation, one rotation, and one scale separately. This can be cleaner or more readable for some codebases.</p>
<p>It also allows us to change one without overriding the other transformations.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">aside</span> <span class="token punctuation">{</span><br /> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">rotate</span><span class="token punctuation">(</span>10deg<span class="token punctuation">)</span><br /><span class="token punctuation">}</span><br /><span class="token selector">aside:hover</span> <span class="token punctuation">{</span><br /> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">scale</span><span class="token punctuation">(</span>.85<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>At first glance, you might expect this element to be rotated 10 degrees and then on hover add a scale down to the original transformation. But properties override, so the rotation is lost on hover. As different states or interactions become more complex it can be complicated to keep all the desired transformations straight.</p>
<p>But with the independent transform properties, we can add or remove individual transformations without affecting the others. So we can slightly alter our code and get a different result where the hover state is both rotated and scaled.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">aside</span> <span class="token punctuation">{</span><br /> <span class="token property">rotate</span><span class="token punctuation">:</span> 10deg<br /><span class="token punctuation">}</span><br /><span class="token selector">aside:hover</span> <span class="token punctuation">{</span><br /> <span class="token property">scale</span><span class="token punctuation">:</span> .85<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>We can also <code>transition</code> or animate each individually. In this example, the scale and translation change on hover with different durations and delays. The rotate does not transition but instead stays unaffected by the other two properties animating.</p>
<p class="codepen" data-height="265" data-theme-id="dark" data-default-tab="css,result" data-user="danwilson" data-slug-hash="wvByMbX" data-editable="true" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Independent Transform Properties">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/wvByMbX">
Independent Transform Properties</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<h3 id="what-are-the-limitations" tabindex="-1">What are the limitations? <a class="direct-link" href="https://danielcwilson.com/blog/2020/02/motion-path-transforms/#what-are-the-limitations" aria-hidden="true">#</a></h3>
<p>These properties do not take a list of options like the original <code>transform</code> property, so you only get one of each type per element. If you want more than that, you will need return to the <code>transform</code>.</p>
<p>They also all share the same <code>transform-origin</code>, so whether you are using the <code>transform</code> property or the three individual properties they all depend on <code>transform-origin</code>.</p>
<p>These properties are always applied in the same order, and they happen before everything in the <code>transform</code> property:</p>
<ol>
<li><code>translate</code></li>
<li><code>rotate</code></li>
<li><code>scale</code></li>
</ol>
<p class="codepen" data-height="455" data-theme-id="dark" data-default-tab="result" data-user="danwilson" data-slug-hash="abzGPmG" style="height: 455px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Visual Reference: Order of translate, rotate, scale">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/abzGPmG">
Visual Reference: Order of translate, rotate, scale</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>If you want to have the rotation applied before a translation, you will need to use the <code>transform</code> property. Either of the following options would support this scenario.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">aside</span> <span class="token punctuation">{</span><br /> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">rotate</span><span class="token punctuation">(</span>30deg<span class="token punctuation">)</span> <span class="token function">translate</span><span class="token punctuation">(</span>10px<span class="token punctuation">,</span>10px<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token comment">/* These are still separate, so you still can work independently */</span><br /><span class="token selector">aside.alternate</span> <span class="token punctuation">{</span><br /> <span class="token property">rotate</span><span class="token punctuation">:</span> 30deg<span class="token punctuation">;</span><br /> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translate</span><span class="token punctuation">(</span>10px<span class="token punctuation">,</span>10px<span class="token punctuation">)</span><br /><span class="token punctuation">}</span></code></pre>
<h3 id="wait...-why-were-the-offset-properties-mentioned-at-the-beginning" tabindex="-1">Wait... why were the <code>offset</code> properties mentioned at the beginning? <a class="direct-link" href="https://danielcwilson.com/blog/2020/02/motion-path-transforms/#wait...-why-were-the-offset-properties-mentioned-at-the-beginning" aria-hidden="true">#</a></h3>
<p>With the <code>transform</code> property we can translate, rotate, scale, and skew our element as we choose, and the <code>offset</code> properties also effectively translate and rotate our element.</p>
<p>Even though it works in a different way, the <code>offset</code> properties all are effectively applying transformations on the coordinate system, in a similar manner to the transforms. As such, they also rely on the same <code>transform-origin</code> that the other four transformation properties use.</p>
<h3 id="when-are-the-offset-properties-applied" tabindex="-1">When are the <code>offset</code> properties applied? <a class="direct-link" href="https://danielcwilson.com/blog/2020/02/motion-path-transforms/#when-are-the-offset-properties-applied" aria-hidden="true">#</a></h3>
<p>The three new independent transform properties happen <em>before</em> the offset properties. The <code>transform</code> functions are applied in order after the <code>offset</code>.</p>
<ol>
<li><code>translate</code></li>
<li><code>rotate</code></li>
<li><code>scale</code></li>
<li><code>offset</code> (distance, anchor, and rotate)</li>
<li><code>transform</code> (functions applied in the order specified)</li>
</ol>
<p>So for example, using a basic <code>offset-path</code> animation will produce a different visual result when you combine it with a <code>transform: translate(25px -35px)</code> versus combining it with a <code>translate: 25px -35px</code>.</p>
<p class="codepen" data-height="404" data-theme-id="dark" data-default-tab="result" data-user="danwilson" data-slug-hash="xxbmZLw" style="height: 404px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="transform:translate vs translate with offset-path">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/xxbmZLw">
transform:translate vs translate with offset-path</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>(I also have a <a href="https://codepen.io/danwilson/pen/KKwXXqN">rotate example with <code>transform-origin</code> thrown in for good measure</a> if you so please).</p>
<p>It is certainly interesting (and often confusing) how these all interact with each other. Knowing the order of transformations, though, is at least half the struggle in clearing up some of the transformation magic happening with <code>transform</code>, independent transform properties, and Motion Path.</p>
Get Moving (or not) with CSS Motion Path2020-01-06T03:01:30Zhttps://danielcwilson.com/blog/2020/01/motion-path-quirks/<p>With the release of <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases/72">Firefox 72 on January 7, 2020</a>, CSS Motion Path is now in Firefox, <a href="https://www.microsoftedgeinsider.com/en-us/">new Edge</a> (slated for a January 15, 2020 stable release), Chrome, and Opera (and other Blink-based browsers). That means each of these browsers supports a common baseline of <code>offset-path: path()</code>, <code>offset-distance</code>, and <code>offset-rotate</code>.</p>
<p>Firefox also released stable support for <code>offset-anchor</code> (currently behind the "Experimental Web Platform Features" flag in Blink-based browsers). To celebrate, let’s review the basics of what is supported, explain some of the specifics when a path is applied, and also highlight the possibilities of <code>offset-anchor</code>.</p>
<p class="codepen" data-height="435" data-theme-id="dark" data-default-tab="css,result" data-user="danwilson" data-slug-hash="rNaGrGo" style="height: 435px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Shape Revealer 2020">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/rNaGrGo">
Shape Revealer 2020</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<h3 id="defining-a-path" tabindex="-1">Defining a path <a class="direct-link" href="https://danielcwilson.com/blog/2020/01/motion-path-quirks/#defining-a-path" aria-hidden="true">#</a></h3>
<p>There technically is no motion involved when using any of the properties defined in the <a href="https://drafts.fxtf.org/motion-1">CSS Motion Path specification</a>. The <code>offset-path</code> property allows you to set up an invisible path that an element <em>can</em> follow.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">#my-element</span> <span class="token punctuation">{</span><br /> <span class="token property">offset-path</span><span class="token punctuation">:</span> <span class="token function">path</span><span class="token punctuation">(</span><span class="token string">'M0,0 C40,160 60,160 100,0'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>If you are familiar with SVG paths, or have explored other places to use the <code>path()</code> function <a href="https://hacks.mozilla.org/2019/12/firefox-71-a-year-end-arrival/">like newer <code>clip-path</code> options</a>, this might seem familiar. This collection of letters, numbers, and commas is a way to specify vectorized lines, curves, and more. This previous example makes a U-shaped curve starting at <code>0px,0px</code> and ending 100px to the right at <code>100px,0px</code>. To learn more about this syntax, check out Joni Trythall’s <a href="http://svgpocketguide.com/book/">SVG Pocket Guide</a> or the <a href="https://css-tricks.com/svg-path-syntax-illustrated-guide/">Illustrated SVG <code>path</code> Syntax Guide</a> on CSS-Tricks.</p>
<p>Some quick basics:</p>
<ul>
<li><code>M 0,0</code> means move to the <code>x, y</code> coordinates of <code>0, 0</code> without drawing anything</li>
<li><code>L 10,10</code> means draw a line from the previous point to <code>10,10</code></li>
<li>Bezier Curves are handled with <code>C</code> and three sets of coordinates.</li>
</ul>
<p>There are many other ways in the CSS Motion Path specification to set an offset path, such as using other CSS Shape functions like <code>circle()</code>, the element’s box, or the new <code>ray()</code> function that introduces polar coordinates to CSS. However, at this time, only <code>path()</code> is supported in all the browsers already mentioned. There is significant progress made with <code>ray()</code> behind flags, so it is likely to be the next to be released.</p>
<h3 id="defining-a-distance" tabindex="-1">Defining a distance <a class="direct-link" href="https://danielcwilson.com/blog/2020/01/motion-path-quirks/#defining-a-distance" aria-hidden="true">#</a></h3>
<p>The offset distance will be any length value, though I would wager that percentages are the most valuable as <code>100%</code> always represents the end of the path. So going halfway along the path is as straightforward as saying <code>50%</code>.</p>
<figure>
<img src="https://danielcwilson.com/img/posts/2020/offsetDistance.jpg" />
<figcaption>The placement of various percentage values for <code>offset-distance</code> on a path. View the <a href="https://codepen.io/danwilson/pen/OJPyKgq">live example on CodePen</a>.</figcaption>
</figure>
<h3 id="animating-along-the-path" tabindex="-1">Animating along the path <a class="direct-link" href="https://danielcwilson.com/blog/2020/01/motion-path-quirks/#animating-along-the-path" aria-hidden="true">#</a></h3>
<p>As stated earlier, the CSS <em>Motion</em> Path spec actually does not provide motion out of the box. We take our path definition and then use the existing tried and true animation methods to animate the value of <code>offset-distance</code>. So to animate an element along its entire path from <code>0%</code> (the default value of <code>offset-distance</code>) to <code>100%</code> we can set up a CSS animation (or use the Web Animations API, <code>requestAnimationFrame</code>, etc.) to modify these values.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">#my-element</span> <span class="token punctuation">{</span><br /> <span class="token property">offset-path</span><span class="token punctuation">:</span> <span class="token function">path</span><span class="token punctuation">(</span><span class="token string">'M0,0 C40,160 60,160 100,0'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property">animation</span><span class="token punctuation">:</span> go 4000ms infinite ease-in-out<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token atrule"><span class="token rule">@keyframes</span> go</span> <span class="token punctuation">{</span><br /> <span class="token selector">100%</span> <span class="token punctuation">{</span><br /> <span class="token property">offset-distance</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p class="codepen" data-height="305" data-theme-id="dark" data-default-tab="css,result" data-user="danwilson" data-slug-hash="xxbwvXX" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Offset-distance in motion">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/xxbwvXX">
Offset-distance in motion</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<h3 id="animating-the-path-itself" tabindex="-1">Animating the path itself <a class="direct-link" href="https://danielcwilson.com/blog/2020/01/motion-path-quirks/#animating-the-path-itself" aria-hidden="true">#</a></h3>
<p>We can also change the path itself, and if it has the same number of data points the brower can interpolate the values and smoothly transition the path. If we start with a simple straigh path defined as <code>path('M0,0 L100,100')</code> (which defines a line segment from <code>0px,0px</code> to <code>100px,100px</code>) we are able to animate it to a new line segment as long as it also has only two points, such as <code>path('M100,0 L0,100')</code>. If you try to go to <code>path('M100,0 L0,100 L100,100')</code> the browser will not be able to determine the in-between values since the paths have a different number of points, so the path will simply toggle between the two definitions instead of smoothly transitioning.</p>
<p class="codepen" data-height="265" data-theme-id="dark" data-default-tab="result" data-user="danwilson" data-slug-hash="3940636b9f1cafe73e6deaab66a26f05" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Animating offset-path">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/3940636b9f1cafe73e6deaab66a26f05">
Animating offset-path</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<h3 id="defining-where-the-element-faces" tabindex="-1">Defining where the element faces <a class="direct-link" href="https://danielcwilson.com/blog/2020/01/motion-path-quirks/#defining-where-the-element-faces" aria-hidden="true">#</a></h3>
<p>By default, the element will "face" the direction of the path, with its right side staying perpendicular to the path at all times. This is thanks to the <code>auto</code> value of the third offset property <code>offset-rotate</code>. If we would rather the element face away from the direction of the path we can use the value <code>reverse</code>.</p>
<p>The <code>offset-rotate</code> property also takes angle values if you want to have the element stay in a fixed direction at a certain angle and not follow the path. With <code>0deg</code>, the element will stay in its original, non-pathed orientation where the right side always continues to face the right regardless the direction of the path.</p>
<p>The last option is to combine the keywords <code>auto</code> or <code>reverse</code> with a second option of an angle. By setting, for example, <code>offset-rotate: auto 90deg</code> the element will rotate to account for the direction of the path, but it will have an added offset of 90 degrees. So by rotating the element a quarter turn, it is now the top side that faces the direction of the path and remains perpendicular to it.</p>
<p class="codepen" data-height="392" data-theme-id="dark" data-default-tab="result" data-user="danwilson" data-slug-hash="83486772c8658352941617062165cd58" style="height: 392px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="offset-rotate vs. transform/rotate">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/83486772c8658352941617062165cd58">
offset-rotate vs. transform/rotate</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>Just as <code>offset-path</code> and <code>offset-distance</code> are animatable, when using angles (even in combination with <code>auto</code>/<code>reverse</code>) the <code>offset-rotate</code> property can be animated.</p>
<h3 id="defining-the-anchor-point-on-the-path" tabindex="-1">Defining the anchor point on the path <a class="direct-link" href="https://danielcwilson.com/blog/2020/01/motion-path-quirks/#defining-the-anchor-point-on-the-path" aria-hidden="true">#</a></h3>
<p>Elements will be centered on the path, but we can change this by setting the <code>offset-anchor</code> property. The types of values are similar to what you see in <code>background-position</code> or a two-dimensional <code>transform-origin</code> where you set the horizontal (x-axis) position and the vertical (y-axis) position. So the default value is <code>offset-anchor: 50% 50%</code> which can also be specified as <code>center center</code>. We can do the <code>top left</code> corner (same as <code>0% 0%</code>) or any other length/percentage value to change the point on the element that anchors to the path. It is even possible to use values outside the bounds of the element with negative numbers or percentages beyond 100%, for example.</p>
<p class="codepen" data-height="405" data-theme-id="dark" data-default-tab="css,result" data-user="danwilson" data-slug-hash="wJRmGz" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Offset Path Anchor">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/wJRmGz">
Offset Path Anchor</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>When the values are lengths or percentages, the anchor property can be animated. Therefore, each of the four <code>offset</code> properties can be animated even though the only one that moves along the path in the traditional sense is <code>offset-distance</code>.</p>
<p class="codepen" data-height="305" data-theme-id="dark" data-default-tab="css,result" data-user="danwilson" data-slug-hash="ZEYJayP" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="animating offset distance, rotate, and anchor" data-editable="true">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/ZEYJayP">
animating offset distance, rotate, and anchor</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<h3 id="why-does-my-element-shift-when-i-only-apply-a-path" tabindex="-1">Why does my element shift when I only apply a path? <a class="direct-link" href="https://danielcwilson.com/blog/2020/01/motion-path-quirks/#why-does-my-element-shift-when-i-only-apply-a-path" aria-hidden="true">#</a></h3>
<p>You might suspect that nothing really happens when you specify a path alone, as it is the distance, rotation, and anchor that affect how an element appears along the path.</p>
<p>The path itself has its <code>0,0</code> coordinates placed at the element’s original placement in the document flow. When specifying only an <code>offset-path</code>, our element is placed at the start of our (invisible) path (<code>offset-distance: 0%</code>). It is very likely the element will visually look different, though, as it is the element’s center point that is placed at the start of the path (<code>offset-anchor: 50% 50%</code>), and its original right side will face the direction of the path (<code>offset-rotate: auto</code>).</p>
<figure>
<img src="https://danielcwilson.com/img/posts/2020/offsetPath.png" />
<figcaption>An element can move from its original location with only an <code>offset-path</code> defined due to the specified starting point and the default values for the other properties. View the <a href="https://codepen.io/danwilson/pen/ExaVBrK">live example on CodePen</a>.</figcaption>
</figure>
<p>If the start of the path is at the top left corner then at a minimum the element will be shifted up and to the left such that the anchor point (at <code>center center</code> by default) is at the top left corner of the element’s original position. If you would rather have the element stay in its initial position at the start, you likely will need to rework the path definition to start at your initial anchor point or work some magic with <code>position</code> or the independent transform properties.</p>
<h3 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://danielcwilson.com/blog/2020/01/motion-path-quirks/#conclusion" aria-hidden="true">#</a></h3>
<p>Those are some key basics, but there are certainly many possibilities to explore. Motion paths are often associated with continuous curves, but there is nothing that says you cannot use straight lines or disconnected paths. Motion paths are typically associated with, well, motion, but <code>offset</code> can provide a unique way to simply position elements statically. The time to explore their possibilities is now.</p>
Animating a Hue around the Color Wheel with Houdini2019-09-14T23:59:30Zhttps://danielcwilson.com/blog/2019/09/huedini/<p>Even though the <code>hsl()</code> color function allows us to specify hue, saturation, and lightness levels individually, there is no straightforward way to animate one value independently of the others. We will explore how color interpolation works on the web, look at our options to animate a hue around a color wheel, and see how Houdini gives us a mechanism to do this.</p>
<h3 id="the-basics-of-hsl" tabindex="-1">The basics of <code>HSL</code> <a class="direct-link" href="https://danielcwilson.com/blog/2019/09/huedini/#the-basics-of-hsl" aria-hidden="true">#</a></h3>
<p>The beauty of defining a color with <code>hsl()</code> is that you can start with a hue and then tweak it. If you want a reddish color you use a hue near <code>0</code>, or a cyan color is on the opposite side of the wheel at <code>180</code> (the values represent degrees in a circle, so the range of different values are from 0 to 360). The other two values are percentages from <code>0%</code> to <code>100%</code>. Saturation shows how full the color is at <code>100%</code> or grayed out more as you approach <code>0%</code>. Lightness at <code>0%</code> is always black, <code>100%</code> is always white, and <code>50%</code> is a good default for getting a bright color.</p>
<p class="codepen" data-height="384" data-theme-id="32298" data-default-tab="result" data-user="danwilson" data-slug-hash="BaBLjjq" style="height: 384px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Visual Reference: Colors via HSL">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/BaBLjjq/">
Visual Reference: Colors via HSL</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<h3 id="color-interpolation" tabindex="-1">Color Interpolation <a class="direct-link" href="https://danielcwilson.com/blog/2019/09/huedini/#color-interpolation" aria-hidden="true">#</a></h3>
<p>Interpolation is effectively how the values between a start and end state are determined during an animation. Browsers are very efficient at determining the values between two numbers such as filling in an opacity animation from <code>0</code> to <code>1</code>.</p>
<p>Determining what colors to show between two color states in an animation is actually also straightforward for a browser to accomplish, as colors boil down to a set of numbers.</p>
<p>With RGB colors like <code>#ffaabb</code> and <code>rgb(255,170,187)</code> we have three sets of numbers that can be interpolated individually to determing a color value at each step in the animation. So if we want to move from a magenta (<code>rgb(255,0,255)</code>) to a cyan (<code>rgb(0,255,255)</code>) the R value will animate from 255 to 0, the G value will go from 0 to 255, while the B value stays at 255. This process is also how the inbetween values are determined for gradients.</p>
<p class="codepen" data-height="404" data-theme-id="32298" data-default-tab="result" data-user="danwilson" data-slug-hash="aboKeqM" style="height: 404px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Color Interpolation">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/aboKeqM/">
Color Interpolation</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>Every step of this transition is still very much a blend of these two colors. With <code>hsl()</code> we get something a little more interesting where you can change a single value (the hue) and potentially get every color of the rainbow. Since we were able to interpolate each of the three RGB parts, you might think the three individual parts of the <code>hsl()</code> will interpolate on their own as well and we could actually rotate around the color wheel simply by animating from <code>hsl(0,100%,50%)</code> to <code>hsl(360,100%,50%)</code>.</p>
<p class="codepen" data-height="265" data-theme-id="0" data-default-tab="css,result" data-user="danwilson" data-slug-hash="21c21aff219e3f5768c1b3cdad362f5e" data-editable="true" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Animating from red to red">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/21c21aff219e3f5768c1b3cdad362f5e/">
Animating from red to red</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>This red block is technically animating, I promise. However, regardless how you define your color, <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#Interpolation">CSS always animates between its computed values in RGB</a> in the sRGB color space. So even though we used HSL in the previous example, it technically is doing an animation from <code>#ff0000</code> to <code>#ff0000</code>. You can edit the example to instead go from a hue of <code>0</code> to a hue of <code>180</code> (cyan) to see it doing the same animation you would find by going <code>red</code> to <code>cyan</code> or <code>#ff0000</code> to <code>#00ffff</code>.</p>
<p>So whether you use named colors, RGB, HSL, or future methods like <a href="https://drafts.csswg.org/css-color/#the-hwb-notation"><code>hwb()</code></a>, the color stops are effectively converted to RGB and then have the interpolation applied.</p>
<p>Is it possible to animate a hue change only?</p>
<h3 id="css-filters-and-hue-rotate" tabindex="-1">CSS Filters and <code>hue-rotate</code> <a class="direct-link" href="https://danielcwilson.com/blog/2019/09/huedini/#css-filters-and-hue-rotate" aria-hidden="true">#</a></h3>
<p>It is! Sort of!</p>
<p>CSS Filters have been well supported for several years now across the board, including non-Chromified-Edge. Most people tend to lean on filters for the <code>blur()</code> function, but there are several other options including <code>hue-rotate()</code>.</p>
<p>This will take the current hue of your color and rotate it around the color wheel the angle of degrees you specify. So let’s try our animation again with a starting <code>hsl(0,100%,50%)</code> and animate the hue to <code>360</code> via <code>hue-rotate(360deg)</code>.</p>
<p class="codepen" data-height="265" data-theme-id="0" data-default-tab="css,result" data-user="danwilson" data-slug-hash="1ec95bee8e9d68c24417335cc9100298" data-editable="true" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Animating from red to red">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/1ec95bee8e9d68c24417335cc9100298/">
Animating from red to red (hue-rotate)</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>We did it!*</p>
<p>With an asterisk!</p>
<p>My goal here was to keep the saturation and lightness consistent and then change only the hue from <code>0</code> to <code>360</code>. The hue was accurately rotated around a color wheel, but if you look closely at the color changes, we should see colors very similar to the perimeter of the circle in the first example of this article, where we can very clearly see each bright color from a rainbow — red, orange, yellow, green, blue, indigo, and violet. This animation clearly has a red, green, and blue, but everything in between is much darker and muddier than I’d expect.</p>
<p>That is because <code>hue-rotate()</code> does not use the same color wheel as you get with <code>hsl()</code> (as <a href="https://codepen.io/noahblon/post/coloring-svgs-in-css-background-images#comment-id-208849">Amelia Bellamy-Royds wonderfully explains</a> in this blog comment). It gets complicated with color spaces and the fact that <code>hue-rotate</code> uses a combination of hue, saturation, and <em>luminance</em> instead of lightness.</p>
<p class="codepen" data-height="334" data-theme-id="32298" data-default-tab="result" data-user="danwilson" data-slug-hash="mxjVYJ" style="height: 334px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="What I Want out of hue-rotate">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/mxjVYJ/">
What I Want out of hue-rotate</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>So this gets us a more interesting color animation, but it is not a rainbow animation at the same saturation and lightness. We can approximate a true hue rotation by using multiple keyframes with different colors. For example we get a little closer if we set an animation with three states of <code>hsl(0,100%,50%)</code>, <code>hsl(120,100%,50%)</code>, <code>hsl(240,100%,50%)</code>. We get even closer as we do five keyframes and ten keyframes. With 36 frames we get an approximation that is very close to the desired result.</p>
<p class="codepen" data-height="265" data-theme-id="0" data-default-tab="css,result" data-user="danwilson" data-slug-hash="aboGJWe" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="HSL: Options to Rotate H with Same SL">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/aboGJWe/">
HSL: Options to Rotate H with Same SL</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<h3 id="the-houdini-rotate" tabindex="-1">The Houdini Rotate <a class="direct-link" href="https://danielcwilson.com/blog/2019/09/huedini/#the-houdini-rotate" aria-hidden="true">#</a></h3>
<p>If you are in a browser that supports the Houdini Properties and Values API specification, you will see an extra animation in the previous example (try a Blink browser with Experimental Web Platform Features flag enabled or the latest Safari Technology Preview). That gives us the actual behavior I desired as it accurately keeps the saturation and lightness in place and interpolates the hue value between <code>0</code> and <code>360</code>.</p>
<p>As we can use <a href="https://danielcwilson.com/blog/2017/04/individualized-properties/">Custom Properties to individualize the parts of a value</a>, we can work with a base <code>hsl(var(--hue),100%,50%)</code> color and modify our <code>--hue</code> to go from <code>0</code> to <code>360</code>. Custom Properties themselves are not animatable out of the box, but Houdini allows the web author to provide a syntax for a specific custom property which tells it the rules to interpolate the property’s value.</p>
<p>With the following CSS, we are changing the hue from <code>0</code> to <code>360</code>. The JavaScript is telling the browser to treat our custom property <code>--hue</code> as a number, and so it can follow the interpolation rules for numbers.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">div</span> <span class="token punctuation">{</span><br /> <span class="token property">--hue</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span><br /> <span class="token property">background</span><span class="token punctuation">:</span> <span class="token function">hsl</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--hue<span class="token punctuation">)</span><span class="token punctuation">,</span> 100%<span class="token punctuation">,</span> 50%<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property">animation</span><span class="token punctuation">:</span> hue-rotate 10000ms infinite linear<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token atrule"><span class="token rule">@keyframes</span> hue-rotate</span> <span class="token punctuation">{</span><br /> <span class="token selector">100%</span> <span class="token punctuation">{</span><br /> <span class="token property">--hue</span><span class="token punctuation">:</span> 360<br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<pre class="language-js"><code class="language-js"><span class="token keyword">if</span> <span class="token punctuation">(</span>window<span class="token punctuation">.</span><span class="token constant">CSS</span> <span class="token operator">&&</span> <span class="token constant">CSS</span><span class="token punctuation">.</span>registerProperty<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token constant">CSS</span><span class="token punctuation">.</span><span class="token function">registerProperty</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br /> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'--hue'</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">syntax</span><span class="token operator">:</span> <span class="token string">'<number>'</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">inherits</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">initialValue</span><span class="token operator">:</span> <span class="token number">0</span><br /> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>And with that we get a true hue rotation that maintains the same saturation and lightness found in our <code>hsl()</code> root color. We can similarly animate along saturation and lightness by setting up custom properties for each and registering the properties in JavaScript with the <code><percentage></code> syntax and an initial value that is a percentage, such as <code>100%</code>.</p>
<p class="codepen" data-height="265" data-theme-id="0" data-default-tab="js,result" data-user="danwilson" data-slug-hash="ZEzjbRe" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="HSL Houdini">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/ZEzjbRe/">
HSL Houdini</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
3D Glasses with Perspective Origin2019-04-15T12:30:30Zhttps://danielcwilson.com/blog/2019/04/optical-fun-3d-glasses/<p class="preamble">This is the fifth article in a <a href="https://danielcwilson.com/tags/illusions">series discussing different optical illusions & mechanical toys</a> and how we can recreate them on the web (and learn from them). Unlike the other articles in this series, the full effects require a physical item — specifically a pair of 3D Glasses with the red and cyan lenses or a Google Cardboard.</p>
<p>The classic-looking red-cyan 3D glasses have been around for <a href="https://en.wikipedia.org/wiki/Anaglyph_3D#History">about a century</a>, and we can build their corresponding images on the web with a little help from 3D Transforms, perspective, and blend modes.</p>
<p class="codepen" data-height="416" data-theme-id="0" data-default-tab="result" data-user="danwilson" data-slug-hash="gyxEdw" style="height:416px;box-sizing:border-box;display:flex;align-items:center;justify-content:center;border:2px solid black;margin:1em 0;padding:1em" data-pen-title="3D Glasses / Google Cardboard Toggle - Black on White">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/gyxEdw/">
3D Glasses / Google Cardboard Toggle - Black on White</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<h3 id="anaglyphs-and-blend-modes" tabindex="-1">Anaglyphs and Blend Modes <a class="direct-link" href="https://danielcwilson.com/blog/2019/04/optical-fun-3d-glasses/#anaglyphs-and-blend-modes" aria-hidden="true">#</a></h3>
<p>A few years ago, <a href="https://una.im/">Una Kravets</a> wrote a great article about how you can use <a href="https://una.im/3d-effect/">blend modes to create your own 3D images</a> - known as anaglyphs. We can take two images, and apply a cyan screen to one and red to the other. These images are then overlayed. The 3D glasses force one eye to see one image, the other eye sees the other image, and the brain does its magic to create apparent depth.</p>
<p>The key to a successful anaglyph is a change in perspective for the images. You can take an photo with a camera having the viewfinder at your left eye (assuming that your camera still has an eye-level <a href="https://en.wikipedia.org/wiki/Viewfinder">viewfinder</a>). Then you can move the viewfinder to your other eye and take the photo again. Your two images will be fairly similar except a slight change in perspective has happened as each eye has a slightly different viewing angle of your subject.</p>
<p>These images can then be placed on top of each other with the appropriate red and cyan screens applied. How far apart the different colors are at given points in the image determines the perceived depth.</p>
<figure>
<img src="https://danielcwilson.com/img/posts/2019/anaglyph.jpg" />
<figcaption>A final anaglyph composed from two separate photos.</figcaption>
</figure>
<h3 id="not-everyone-has-the-luxury-of-a-viewfinder" tabindex="-1">Not everyone has the luxury of a viewfinder <a class="direct-link" href="https://danielcwilson.com/blog/2019/04/optical-fun-3d-glasses/#not-everyone-has-the-luxury-of-a-viewfinder" aria-hidden="true">#</a></h3>
<p>We don’t even need a camera, because on the web we have 3D Transforms... with built-in perspective. As objects in a line get further away (such as with a negative <code>translateZ</code> value) they appear smaller and ultimately resolve towards a <a href="https://www.merriam-webster.com/dictionary/vanishing%20point">vanishing point</a>, giving us perspective for a given scene.</p>
<figure>
<img src="https://danielcwilson.com/img/posts/2019/perspective-origin.jpg" />
<figcaption>Boxes in parallel lines moving away from the viewer ultimately appear to meet.</figcaption>
</figure>
<p>Individual elements can share the same 3D space, and they can therefore also share the same <code>perspective</code>. We can set our <a href="https://tympanus.net/codrops/css_reference/perspective/"><code>perspective</code> property</a> with a length value that ultimately shows how exaggerated our 3D depth effect is. By default our effective vanishing point is in the center of the 3D space. However, we have ways to control this point via the <code>perspective-origin</code> property. With the exact same <code>transform</code> value we can get very different looking scenes by <a href="https://codepen.io/danwilson/pen/zXYNao">changing only our <code>perspective-origin</code></a>.</p>
<figure class="grid">
<img src="https://danielcwilson.com/img/posts/2019/perspective-origin2050.jpg" />
<img src="https://danielcwilson.com/img/posts/2019/perspective-origin5020.jpg" />
<img src="https://danielcwilson.com/img/posts/2019/perspective-origin8080.jpg" />
<figcaption>The same 3d transforms with <code>perspective-origin</code> values of <code>20% 50%</code>, <code>50% 20%</code>, and <code>80% 80%</code>. Explore more in the <a href="https://codepen.io/danwilson/pen/zXYNao">live perspective-origin demo</a>.</figcaption>
</figure>
<h3 id="doubling-the-perspective" tabindex="-1">Doubling the perspective <a class="direct-link" href="https://danielcwilson.com/blog/2019/04/optical-fun-3d-glasses/#doubling-the-perspective" aria-hidden="true">#</a></h3>
<p>Much like we can take two photos from a slightly different perspective, we can create two scenes and adjust the perspective slightly. We can set up two containing scenes — one for our left eye and one for our right eye. We will give each scene the same <code>perspective</code> value, and each object within each will have the same transforms applied as their duplicated counterpart in the other scene. All objects can share their respective scene’s shared 3D space via <code>transform-style: preserve-3d</code>.</p>
<p>The only difference in the compososition of the scenes will be the <code>perspective-origin</code>. We can set one to be slightly greater than center horizontally, and the other to be slightly less. With CSS Variables (Custom Properties):</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.scene</span> <span class="token punctuation">{</span><br /> <span class="token property">perspective-origin</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--origin-x<span class="token punctuation">)</span> 50%<span class="token punctuation">;</span><br /> <span class="token property">perspective</span><span class="token punctuation">:</span> 20vmin<span class="token punctuation">;</span><br /> <span class="token property">--diff</span><span class="token punctuation">:</span> 6px<span class="token punctuation">;</span><br /> <span class="token property">--origin-x</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>50% - <span class="token function">var</span><span class="token punctuation">(</span>--diff<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token selector">.scene:nth-of-type(2)</span> <span class="token punctuation">{</span><br /> <span class="token property">--origin-x</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>50% + <span class="token function">var</span><span class="token punctuation">(</span>--diff<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>The <code>6px</code> is a value I chose after some experimenting, though there is surely a more mathematical way to choose that based on distance between the eye and the screen. Other values produce slightly different effects, so it’s worth exploring the difference with other values.</p>
<h3 id="filtering-for-the-eyes" tabindex="-1">Filtering for the eyes <a class="direct-link" href="https://danielcwilson.com/blog/2019/04/optical-fun-3d-glasses/#filtering-for-the-eyes" aria-hidden="true">#</a></h3>
<p>Now that we have two overlapping scenes with a slightly different perspective, the second biggest piece of the puzzle is making sure each eye can only see the appropriate scene through the 3D glasses. It is time to create the anaglyph. We will assume our glasses have the red lens on the left eye.</p>
<p>Which color goes where depends on if you want to create a dark foreground with a light background or the inverse.</p>
<p>For starters, let’s assume we have black outlines on a white background. If you are using basic shapes and outlines you can set the <code>red</code> and <code>cyan</code> colors directly on your elements. The elements in your left scene get cyan, the right ones get red. Then we apply a <code>mix-blend-mode: multiply</code> to the scenes. This will make any area where the red and cyan overlap turn black. When looking through the red lens, your eye will be able to see anything that is black or cyan, and your other eye will only see the red and black through the cyan lens. This relies on the same blend mode math as the <a href="https://danielcwilson.com/blog/2018/02/optical-fun-red-reveal">Red Reveal lens</a> effect.</p>
<p class="codepen" data-height="416" data-theme-id="0" data-default-tab="result" data-user="danwilson" data-slug-hash="gyxEdw" style="height:416px;box-sizing:border-box;display:flex;align-items:center;justify-content:center;border:2px solid black;margin:1em 0;padding:1em" data-pen-title="3D Glasses / Google Cardboard Toggle - Black on White">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/gyxEdw/">
3D Glasses / Google Cardboard Toggle - Black on White</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>If you want to have a white foreground on a black background, the colors are reversed — red on the left and cyan on the right. We also change our blend mode to a <code>screen</code> as it similarly looks at where cyan and red overlap and turns those areas white. Now your cyan lens will reveal everything that is cyan or white, and the red lens will reveal everything that is red or white.</p>
<p class="codepen" data-height="416" data-theme-id="0" data-default-tab="result" data-user="danwilson" data-slug-hash="MRmXYp" style="height:416px;box-sizing:border-box;display:flex;align-items:center;justify-content:center;border:2px solid black;margin:1em 0;padding:1em" data-pen-title="3D Glasses / Google Cardboard Toggle">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/MRmXYp/">
3D Glasses / Google Cardboard Toggle</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>If we want to work with more than just black and white, we can introduce additional blend modes. For a dark background, we will apply a cyan screen over our left scene, and a red screen over the second scene. This can be achieved with a cover for each scene of the given color and a <code>mix-blend-mode: screen</code>.</p>
<p>Then, to make sure the bottom image still shows through, we apply a <code>mix-blend-mode: multiply</code> to the whole top scene. This combination of blend modes lets you still make out how the original scene is supposed to look, and it gets that classic every-object-has-some-red-and-some-cyan look. The additional blend mode math in this case is similar to the discussion in constructing a <a href="https://danielcwilson.com/blog/2018/02/optical-fun-barrier-grid">Barrier Grid animation</a> image.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.scene::after</span> <span class="token punctuation">{</span><br /> <span class="token property">content</span><span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">;</span><br /> <span class="token property">position</span><span class="token punctuation">:</span> absolute<span class="token punctuation">;</span><br /> <span class="token property">top</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span><br /> <span class="token property">right</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span><br /> <span class="token property">bottom</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span><br /> <span class="token property">left</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span><br /> <span class="token property">z-index</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span><br /> <span class="token property">background</span><span class="token punctuation">:</span> cyan<span class="token punctuation">;</span><br /> <span class="token property">mix-blend-mode</span><span class="token punctuation">:</span> screen<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token selector">.scene:nth-of-type(2)::after</span> <span class="token punctuation">{</span><br /> <span class="token property">background</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token selector">.scene:nth-of-type(2)</span> <span class="token punctuation">{</span><br /> <span class="token property">mix-blend-mode</span><span class="token punctuation">:</span> multiply<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p class="codepen" data-height="360" data-theme-id="0" data-default-tab="result" data-user="danwilson" data-slug-hash="XQNxbO" style="height: 360px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1em 0; padding: 1em;" data-pen-title="3D Glasses: Radical Mathematical - Basics">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/XQNxbO/">
3D Glasses: Radical Mathematical - Basics</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<h3 id="animating-with-3d-3d-transforms" tabindex="-1">Animating with 3D 3D Transforms <a class="direct-link" href="https://danielcwilson.com/blog/2019/04/optical-fun-3d-glasses/#animating-with-3d-3d-transforms" aria-hidden="true">#</a></h3>
<p>Since we are already positioning everything in our scene with 3D Transforms, we can even animate our scene and take further advantage of the perspective. Performance can be affected as we are doing duplicate animations in a 3D space, and those animations are happening behind blend modes.</p>
<p class="codepen" data-height="360" data-preview="true" data-theme-id="0" data-default-tab="result" data-user="danwilson" data-slug-hash="drRQXK" style="height: 360px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1em 0; padding: 1em;" data-pen-title="3D Glasses: Radical Mathematical">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/drRQXK/">
3D Glasses: Radical Mathematical</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<h3 id="google-cardboard" tabindex="-1">Google Cardboard <a class="direct-link" href="https://danielcwilson.com/blog/2019/04/optical-fun-3d-glasses/#google-cardboard" aria-hidden="true">#</a></h3>
<p>Even if you are unable to find a place to sell you cheap 3D glasses, you are in luck if you own a not-as-cheap-but-still-not-exorbitant version of <a href="https://vr.google.com/cardboard/get-cardboard/">Google Cardboard</a>. It uses similar alignment of images based on altering viewing angles between the eyes. Except here the images are not overlayed, they appear side by side. This example uses the same perspective origin offset, and presents the two scenes side by side. They seem identical while they are apart, but the minor offset is just enough to give an additional illusion of depth when palced inside a Cardboard device.</p>
<p class="codepen" data-height="360" data-preview="true" data-theme-id="0" data-default-tab="result" data-user="danwilson" data-slug-hash="MxLPqQ" style="height: 360px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1em 0; padding: 1em;" data-pen-title="Google Cardboard: Cube">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/MxLPqQ/">
Google Cardboard: Cube</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>Rest assured: If as a society we figure out how to fit two tiny web browsers inside a classic <a href="https://en.wikipedia.org/wiki/View-Master">View-Master</a> reel then I will update this article as it could use similar perspective origin magic.</p>
Jumps: The New Steps() in Web Animation2019-02-24T14:16:01Zhttps://danielcwilson.com/blog/2019/02/step-and-jump/<p>The first big change to web animation easings (aka timing functions) is upon us. After some <a href="https://github.com/w3c/csswg-drafts/issues/1680">discussions</a>, updates to the <a href="https://drafts.csswg.org/css-easing-1/#step-timing-function">specification</a>, and initial implementations as a separate function, Firefox 65 introduces four new options for the <code>steps()</code> function.</p>
<ul>
<li><code>jump-start</code></li>
<li><code>jump-end</code></li>
<li><code>jump-both</code></li>
<li><code>jump-none</code></li>
</ul>
<p class="codepen" data-height="544" data-theme-id="0" data-default-tab="result" data-user="danwilson" data-slug-hash="gqOBJd" style="height: 544px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1em 0; padding: 1em;" data-pen-title="Visual Reference: Steps() and Other Easings, Translate">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/gqOBJd/">
Visual Reference: Steps() and Other Easings, Translate</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>How do these new values compare to what we already had, and when are the best times to use each one?</p>
<h3 id="easings-and-the-steps()-function" tabindex="-1">Easings and the <code>steps()</code> function <a class="direct-link" href="https://danielcwilson.com/blog/2019/02/step-and-jump/#easings-and-the-steps()-function" aria-hidden="true">#</a></h3>
<p>First, let’s take a step back and discuss what <a href="https://css-tricks.com/reversing-an-easing-curve/">easings even are</a> and what the <code>steps()</code> function allows us to do.</p>
<p>Easings allow us to change how a <code>transition</code>, CSS <code>animation</code>, or Web Animations API animation completes over time.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.mover</span> <span class="token punctuation">{</span><br /> <span class="token property">animation</span><span class="token punctuation">:</span> move 2000ms<span class="token punctuation">;</span><br /> <span class="token property">animation-timing-function</span><span class="token punctuation">:</span> linear<span class="token punctuation">;</span> <span class="token comment">/* easing */</span><br /> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateX</span><span class="token punctuation">(</span>0px<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token atrule"><span class="token rule">@keyframes</span> move</span> <span class="token punctuation">{</span><br /> <span class="token selector">100%</span> <span class="token punctuation">{</span><br /> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateX</span><span class="token punctuation">(</span>200px<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>With a <code>linear</code> easing, everything moves at a steady pace. If we change that to <code>ease-in</code> we will have something that starts slower and speeds up as it gets to the end of its animation.</p>
<p>Steps are a bit different, as we can tell the animation to have a specific number of distinct frames. So changing the easing to <code>steps(2)</code>, for example, would give an animation with only two states, a starting position and an ending one.</p>
<p>How <code>steps()</code> determines each step interval is based on a second (and optional) parameter. This is where our new values come into play and join the two existing values — <code>start</code> and <code>end</code>.</p>
<h3 id="starts-and-ends" tabindex="-1">Starts and Ends <a class="direct-link" href="https://danielcwilson.com/blog/2019/02/step-and-jump/#starts-and-ends" aria-hidden="true">#</a></h3>
<p>Instead of diving into what <code>start</code> and <code>end</code> mean, let’s cut to the chase to say that two of the four aforementioned new values are in fact aliases of these original values:</p>
<ul>
<li><code>jump-start === start</code></li>
<li><code>jump-end === end</code></li>
</ul>
<p>The <code>jump</code> prefix helps us explain the words start and end more effectively. When we use <code>start</code> or <code>jump-start</code> we are telling the calculation to skip the starting position. With <code>end</code>/<code>jump-end</code> we want to skip the ending position.</p>
<p>You can think of the <code>steps(n)</code> function as taking snapshots of an animation with a <code>linear</code> easing at the specified intervals and displaying that snapshot until it is time to show the next snapshot. So when we say we want <code>steps(4, jump-end)</code> we will get an animation that divides our animation into four sections and snapshots the initial position of each of those fourths. With <code>steps(5, jump-start)</code> we get an animation divided into five parts, and we take the final position in each part.</p>
<p class="codepen" data-height="376" data-theme-id="0" data-default-tab="result" data-user="danwilson" data-slug-hash="OdyaMz" style="height: 376px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1em 0; padding: 1em;" data-pen-title="Visual Reference: Jump Start, Jump End, Linear">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/OdyaMz/">
Visual Reference: Jump Start, Jump End, Linear</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>Why would you want to skip a beginning or ending state? We are telling the browser to go from a specific state to a different specific state with our animation keyframes, so wouldn’t we always want both those states represented in our resulting animation?</p>
<h4 id="rotations" tabindex="-1">Rotations <a class="direct-link" href="https://danielcwilson.com/blog/2019/02/step-and-jump/#rotations" aria-hidden="true">#</a></h4>
<p>It becomes clearer to realize the benefits of skipping a start or end when you think about the seconds hand on a clock — we’d probably want an animation running for 60 seconds for a full rotation (<code>0deg</code> to <code>360deg</code>), and an easing of <code>steps(60)</code>. This gives us a clock with a second hand that steps to each mark on the clock (<code>jump-end</code>/<code>end</code> is assumed when no second parameter is specified). Without the jumping of the end state, we would have an animation where the start <em>and</em> end would be at the top (<code>0deg</code>), and thus our clock would not be natural as it would stay at the top for two seconds and do the other 58 seconds in between.</p>
<p class="codepen" data-height="400" data-theme-id="0" data-default-tab="result" data-user="danwilson" data-slug-hash="YBzvQQ" style="height: 392px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1em 0; padding: 1em;" data-pen-title="Visual Reference: Steps() and Other Easings, Full Rotation">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/YBzvQQ/">
Visual Reference: Steps() and Other Easings, Full Rotation</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<h4 id="sprites" tabindex="-1">Sprites <a class="direct-link" href="https://danielcwilson.com/blog/2019/02/step-and-jump/#sprites" aria-hidden="true">#</a></h4>
<p>Another important reason is animating with sprites. You can have a strip of frames to animate and transform the position from <code>translateX(0)</code> to <code>translate(-100%)</code> (or use background positions, etc). If you translate a full <code>100%</code> of the width, the final state will be out of view, so we again jump the end, and we can magically capture each frame.</p>
<p class="codepen" data-height="403" data-theme-id="0" data-default-tab="result" data-user="danwilson" data-preview="true" data-slug-hash="wNMMYv" style="height: 403px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1em 0; padding: 1em;" data-pen-title="Visual Reference: Steps + Sprites">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/wNMMYv/">
Visual Reference: Steps + Sprites</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>This keeps us from having to do extra math to prevent the final (blank) frame from showing.</p>
<h3 id="jumping-none" tabindex="-1">Jumping none <a class="direct-link" href="https://danielcwilson.com/blog/2019/02/step-and-jump/#jumping-none" aria-hidden="true">#</a></h3>
<p>Ah, yes. The new stuff.</p>
<p>Sometimes skipping a state really is not what we are looking for. The new option <code>jump-none</code> allows an animation that does not jump the start or the end. For any animation with a step count of at least two, the begining state and the ending state will be represented. The remaining steps will be distributed evenly between. Three steps will have their effective snapshots taken at <code>0%</code>, <code>50%</code>, and <code>100%</code>.</p>
<h4 id="moving-an-object" tabindex="-1">Moving an object <a class="direct-link" href="https://danielcwilson.com/blog/2019/02/step-and-jump/#moving-an-object" aria-hidden="true">#</a></h4>
<p>A straightforward case for this option is moving an object across a screen. We might want to move an object from point A to point B with a stepped effect. Previously with only the jumping of <code>start</code> or <code>end</code> available, there was not a straightforward way to tell the animation to show the starting and ending positions with equal frames in between. The addition of <code>jump-none</code> now gives us this ability.</p>
<p class="codepen" data-height="267" data-theme-id="0" data-default-tab="result" data-user="danwilson" data-slug-hash="BMrBxv" style="height: 267px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1em 0; padding: 1em;" data-pen-title="Visual Reference: jump-none vs linear easing">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/BMrBxv/">
Visual Reference: jump-none vs linear easing</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>With the old ways of <code>steps()</code>, you would usually still be able to achieve this, but you would need to do some extra math and make the translation technically go beyond your visual start or end state. Now it is more straightforward as you can be confident your start and end states are what you explicitly make them.</p>
<h4 id="opacity" tabindex="-1">Opacity <a class="direct-link" href="https://danielcwilson.com/blog/2019/02/step-and-jump/#opacity" aria-hidden="true">#</a></h4>
<p>Opacity also can benefit from making sure the start and end states are always visible. Say we want to do a fade out via a stepped opacity animation from <code>1</code> to <code>0</code>. With jumping <code>start</code> or <code>end</code>, either the fully opaque or the fully transparent state will never be seen. But <code>jump-none</code> make sure both are seen. An animation with <code>steps(2, jump-none)</code> will have a straight on/off animation (to create a clean <a href="https://danielcwilson.com/blog/2018/08/optical-fun-zoetrope/">strobe</a>), and <code>steps(4,jump-none)</code> will give us opacities of <code>1</code>, <code>.6667</code>, <code>.3333</code> and <code>0</code>.</p>
<p class="codepen" data-height="361" data-theme-id="0" data-default-tab="result" data-user="danwilson" data-slug-hash="mvPKwZ" style="height: 361px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1em 0; padding: 1em;" data-pen-title="Visual Reference: Steps() with Opacity">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/mvPKwZ/">
Visual Reference: Steps() with Opacity</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<h3 id="jumping-both" tabindex="-1">Jumping Both <a class="direct-link" href="https://danielcwilson.com/blog/2019/02/step-and-jump/#jumping-both" aria-hidden="true">#</a></h3>
<p>We’ve jumped starts, we’ve jumped ends, and we’ve jumped neither one, which leaves us with jumping both.</p>
<p class="codepen" data-height="381" data-theme-id="0" data-default-tab="result" data-user="danwilson" data-slug-hash="yZmmgN" style="height: 381px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1em 0; padding: 1em;" data-pen-title="Visual Reference: jump-both vs linear easing">
<span>See the Pen <a href="https://codepen.io/danwilson/pen/yZmmgN/">
Visual Reference: jump-both vs linear easing</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>)
on <a href="https://codepen.io/">CodePen</a>.</span>
</p>
<p>I will be interested to see the use cases for this animation. On the one hand it allows for completeness (since we are adding a <code>none</code>, we might as well add a <code>both</code>), but it also has potential as easing options might be used <a href="https://github.com/w3c/csswg-drafts/issues/1332">outside</a> <a href="https://github.com/w3c/csswg-drafts/issues/1371">animation</a>. The use cases for using easings in the context of gradients seem more compelling (to me, in the moment I write these words), than what <code>jump-both</code> provides in the context of animation.</p>
<h3 id="browser-support" tabindex="-1">Browser Support <a class="direct-link" href="https://danielcwilson.com/blog/2019/02/step-and-jump/#browser-support" aria-hidden="true">#</a></h3>
<p>Chrome already implemented the <code>jump-none</code> behavior under the older <code>frames()</code> spec discussion, so I suspect it will not be a huge lift to move it into the new naming. Webkit and EdgeHTML do not have it in any preview versions yet. So it is time to familiarize and experiment rather than go all in without fallbacks.</p>
Clip Paths Know No Bounds2018-12-24T00:00:00Zhttps://danielcwilson.com/blog/2018/12/clip-path/<p>I had the pleasure to write the 20th article for 24 ways this year with <a href="https://24ways.org/2018/clip-paths-know-no-bounds/">Clip Paths Know No Bounds</a> — thinking outside the box when using the <code>clip-path</code> property.</p>
<ul>
<li>Making an octagon with only four points</li>
<li>Creating multiple shapes from a single <code>clip-path</code> polygon</li>
<li>Slicing an image</li>
<li>Different shapes by fill rule</li>
<li>Combining with blend modes and filters</li>
<li>Animating as a content reveal</li>
</ul>
<p><a href="https://24ways.org/2018/clip-paths-know-no-bounds/">View Article on 24ways.org →</a></p>
Animation at Work: September 2018 Edition2018-10-06T00:00:00Zhttps://danielcwilson.com/blog/2018/10/animation-at-work-4/<p class="preamble">This is a repost of the September 2018 Edition of the <a href="http://webanimationweekly.com/">Animation at Work</a> newsletter where I was Guest Editor.</p>
<p>I love exploring the next level of tools we have available to build interactive animations on the web. With Chrome, Firefox, Safari, and Edge giving us early access to their Canary, Nightly, Technology Preview, and Insider Preview versions respectively, we can start exploring features that are on the path to stable browsers. Often we get to see how the standards even evolve as they start iterating on implementations.</p>
<p>Here are some of the _ new things in browsers _ that I’m most excited about, centered around web APIs, CSS Houdini, and Canvas.</p>
<h3 id="web-animations-api" tabindex="-1">Web Animations API <a class="direct-link" href="https://danielcwilson.com/blog/2018/10/animation-at-work-4/#web-animations-api" aria-hidden="true">#</a></h3>
<p>The Web Animations API (WAAPI) is <a href="https://webkit.org/blog/8343/web-animations-in-webkit/">coming to WebKit/Safari</a>, and it’s further along than you might realize.</p>
<p>Safari will join the existing WAAPI implementations in Firefox and Blink browsers, so if you haven’t already, it might be time to start exploring it. For the best starting point, check out the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API/Using_the_Web_Animations_API">guide on MDN</a> from <a href="https://rachelnabors.com/">Rachel Nabors</a>.</p>
<p>If you want to dive into some of the future features (already in Firefox Nightly), you can explore how the WAAPI will let you smoothly <a href="https://css-tricks.com/additive-animation-web-animations-api/">modify already running animations</a>.</p>
<h3 id="houdini-and-custom-properties" tabindex="-1">Houdini & Custom Properties <a class="direct-link" href="https://danielcwilson.com/blog/2018/10/animation-at-work-4/#houdini-and-custom-properties" aria-hidden="true">#</a></h3>
<p>Vincent De Oliveira’s ever-growing <a href="https://css-houdini.rocks/">Houdini playground</a> is here to introduce you to many different facets of CSS Houdini. You can learn the basics (and the more-than-basics) around its different specs/APIs.</p>
<p>CSS Houdini allows us to build on the power of Custom Properties (CSS Variables) by letting us animate them directly inside keyframes, as shown by Ana Tudor animating <a href="https://css-tricks.com/the-state-of-changing-gradients-with-css-transitions-and-animations/">gradients</a> and <a href="https://css-tricks.com/what-houdini-means-for-animating-transforms/">transform functions</a> individually.</p>
<p>There are more people exploring the possibilities of <a href="https://codepen.io/collection/XwgeMo/">animating Custom Properties in this collection</a> of demos on CodePen.</p>
<h3 id="variable-fonts" tabindex="-1">Variable Fonts <a class="direct-link" href="https://danielcwilson.com/blog/2018/10/animation-at-work-4/#variable-fonts" aria-hidden="true">#</a></h3>
<p>Even fonts are getting into the animation game in new ways with <a href="https://codepen.io/collection/XqRLMb/">Variable Fonts</a> as Mandy Michael demonstrates in her impressive experiments.</p>
<h3 id="workers-and-worklets" tabindex="-1">Workers and Worklets <a class="direct-link" href="https://danielcwilson.com/blog/2018/10/animation-at-work-4/#workers-and-worklets" aria-hidden="true">#</a></h3>
<p>For Canvas drawing, we have a new OffscreenCanvas option to <a href="https://developers.google.com/web/updates/2018/08/offscreen-canvas">offload work to a worker</a> and keep our main browser thread free for other logic/interactions. And it pairs nicely with progressive enhancement and feature detection while it makes its way into more browsers.</p>
<p>Speaking of sending work away from the main thread, have you seen that <a href="https://houdini.glitch.me/animation/">Houdini is introducing an Animation Worklet</a>, and it includes initial implementation discussion points around scroll-based timelines?</p>
Morphing Images with Lenticular Printing: Illusions on the Web Part 42018-09-09T00:00:00Zhttps://danielcwilson.com/blog/2018/09/optical-fun-morphing/<p class="preamble">This is the fourth in an <a href="https://danielcwilson.com/tags/illusions">article series discussing different optical illusions & mechanical toys</a> and how we can recreate them on the web (and learn from them). The end result of this article can be seen as a <a href="https://lenticular.glitch.me/">standalone, fullscreen demo</a> or with the <a href="https://codepen.io/danwilson/pen/rrYQyP/">code and result side by side</a>.</p>
<p>Perhaps you’ve seen them when you collected <a href="https://duckduckgo.com/?q=lenticular+baseball+cards&iax=images&ia=images">trading cards</a> in the 90s, more recently seen them on <a href="https://duckduckgo.com/?q=lenticular+bluray+covers&iar=images&iax=images&ia=images">Bluray covers</a>, or have them on that Best Buy gift card that you never used. As your viewing angle changes (or you physically rotate the item), an image morphs into a new one, a 3D effect might be achieved, or a small animation may occur. Sometimes referred as tilt cards or holograms, the approach we are recreating today is more formally associated with <a href="https://en.wikipedia.org/wiki/Lenticular_printing">Lenticular printing</a>.</p>
<h3 id="lenticular-printing" tabindex="-1">Lenticular Printing <a class="direct-link" href="https://danielcwilson.com/blog/2018/09/optical-fun-morphing/#lenticular-printing" aria-hidden="true">#</a></h3>
<p>The way these physical cards are made involves a special printing surface with thin rows of lenses that affect what you see from a given angle. When you see one up close it is clear there are a series of lines that create the magic, and depending on your angle you might be able to see chopped versions of multiple images at a given time.</p>
<p>When moving this to the digital realm, we don’t really have a concept of the lens to affect what you see. But the web does have ways to split an image into smaller chunks and layers of 3d transforms to affect our viewing angle.</p>
<p data-height="375" data-theme-id="32298" data-slug-hash="YOEmjm" data-default-tab="result" data-user="danwilson" data-pen-title="Lenticular Card: Noninteractive" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/YOEmjm/">Lenticular Card: Noninteractive</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<h3 id="splitting-the-images" tabindex="-1">Splitting the images <a class="direct-link" href="https://danielcwilson.com/blog/2018/09/optical-fun-morphing/#splitting-the-images" aria-hidden="true">#</a></h3>
<p>I am exploring the morphing between two images in this example. Starting with two images on top of each other, we then split both of them into tiny strips three pixels wide. I usually go with viewport units for something like this so that the central demo will scale nicely, but in keeping track of the width of the strips, I opted for fixed pixels everywhere. Let’s call this container that holds the two images our "card."</p>
<p>We can split each image a number of ways, but here it is structured as an unordered list and each strip is a list item. Since there are only two images, we can take advantage of each list item’s pseudoelements. Each list item in the <code>::before</code> sets one of the images as its background, and the other image is similarly set in the <code>::after</code>. Custom Properties (CSS Variables) then allow us to offset the <code>background-position</code> for each list item so that the result is the full image.</p>
<p data-height="275" data-theme-id="0" data-slug-hash="oPpvzg" data-default-tab="css,result" data-user="danwilson" data-pen-title="Lenticular Card: Split Images" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/oPpvzg/">Lenticular Card: Split Images</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<p>This is a fairly manual approach to show what all is happening. To keep things cleaner we could use Pug or another templating engine to simplify the markup and assign an index as a Custom Property that we could use to drive the <code>background-position</code>. Also, there is the new <a href="https://splitting.js.org/">Splitting.js</a> library that generates elements and helpful Custom Properties from a single element with an image.</p>
<h3 id="showing-both-images-at-the-same-time" tabindex="-1">Showing both images at the same time <a class="direct-link" href="https://danielcwilson.com/blog/2018/09/optical-fun-morphing/#showing-both-images-at-the-same-time" aria-hidden="true">#</a></h3>
<p>Now that we have two images split into thin columns and on top of each other we can start working with angles and perspective. With a perspective set on the body, and a <code>transform-style: preserve-3d</code> down through the <code>ul</code> and each <code>li</code> we can know that all our 3D rotations will work in relation to each other (inside the same 3D space).</p>
<p>Since we do not have a direct concept of the fancy thin lenses in our browser, we will try to achieve something similar by rotating each strip 60 degrees around the Y axis away from us (with each pseudoelement rotating from opposite sides of the strip). We can make a blended photo with little triangles where a little of each image strip is seen at a given time.</p>
<p data-height="300" data-theme-id="32298" data-slug-hash="JaJwRP" data-default-tab="result" data-user="danwilson" data-pen-title="Lenticular Cards: Zoomed" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/JaJwRP/">Lenticular Cards: Zoomed</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">li::before, li::after</span> <span class="token punctuation">{</span><br /> <span class="token property">content</span><span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">;</span><br /> <span class="token property">position</span><span class="token punctuation">:</span> absolute<span class="token punctuation">;</span><br /> <span class="token property">top</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span> <span class="token property">left</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span> <span class="token property">right</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span> <span class="token property">bottom</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token selector">li::before</span> <span class="token punctuation">{</span><br /> <span class="token property">background-image</span><span class="token punctuation">:</span> <span class="token url"><span class="token function">url</span><span class="token punctuation">(</span>https://images.unsplash.com/photo-1473580044384-7ba9967e16a0?ixlib=rb-0.3.5&q=85&fm=jpg&crop=entropy&cs=srgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ&s=53a6022c048f8595d90636e94b7fabf3<span class="token punctuation">)</span></span><span class="token punctuation">;</span><br /> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">rotateY</span><span class="token punctuation">(</span>-60deg<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property">transform-origin</span><span class="token punctuation">:</span> 100% 50%<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token selector">li::after</span> <span class="token punctuation">{</span><br /> <span class="token property">background-image</span><span class="token punctuation">:</span> <span class="token url"><span class="token function">url</span><span class="token punctuation">(</span>https://images.unsplash.com/photo-1522735555435-a8fe18da2089?ixlib=rb-0.3.5&q=85&fm=jpg&crop=entropy&cs=srgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ&s=d404d2ca601ddb2b3b33c4e3f41291b4<span class="token punctuation">)</span></span><span class="token punctuation">;</span><br /> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">rotateY</span><span class="token punctuation">(</span>60deg<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property">transform-origin</span><span class="token punctuation">:</span> 0% 50%<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<h3 id="tilting-the-image" tabindex="-1">Tilting the image <a class="direct-link" href="https://danielcwilson.com/blog/2018/09/optical-fun-morphing/#tilting-the-image" aria-hidden="true">#</a></h3>
<p>Now that we have our base card constructed (such that a little of each image is shown when we look at the card straight on) we can talk about perspective. Our <code>perspective-origin</code> is set to be in the center of the <code>body</code>, and as we rotate the card around the Y axis at its center we can achieve our morphing image effect. As we rotate in one direction more of image A is covered up, revealing more of image B. As we switch and rotate in the other direction image B gets more covered up, showing more of image A.</p>
<p>We are only moving the card itself. There are many transforms used to create the structure of the card, but the only element that moves is our card (the unordered list).</p>
<p>In between we even get a kind of sheen effect because of all the strips fighting for attention and the renderer trying to get the right pixels to display. Our final images are not perfect (you can see artifacts and some lines between strips), but the same is true when printed in the physical world.</p>
<p data-height="300" data-theme-id="32298" data-slug-hash="rrYQyP" data-default-tab="js,result" data-user="danwilson" data-pen-title="Lenticular Card" data-preview="true" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/rrYQyP/">Lenticular Card</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<p>You can use mouse/stylus/touch if your browser supports Pointer Events (<a href="https://caniuse.com/#search=pointer%20events">sorry, Safari users</a>) to rotate the card by dragging horizontally.</p>
<p>You can also load <a href="https://lenticular.glitch.me/">the full demo</a> up outside of an iframe to use on a device supporting deviceorientation events (<a href="https://caniuse.com/#search=deviceorientation">you are welcome, Safari users</a>). It is best to lock the device orientation.</p>
<h3 id="what-are-the-more...-straightforward-options" tabindex="-1">What are the more... straightforward options? <a class="direct-link" href="https://danielcwilson.com/blog/2018/09/optical-fun-morphing/#what-are-the-more...-straightforward-options" aria-hidden="true">#</a></h3>
<p>There are several ways to swap between two images. One could overlay two <code>img</code> elements and fade the top one in and out with an <code>opacity</code> animation.</p>
<p data-height="250" data-theme-id="0" data-slug-hash="VGyaPv" data-default-tab="css,result" data-user="danwilson" data-pen-title="Lenticular Card: But Not" data-preview="true" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/VGyaPv/">Lenticular Card: But Not</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<p>Or in certain browsers you can explore doing something similar directly with layered background images. There is a <code>cross-fade</code> function that can let you have two images mixed together such that the top one has a partial opacity, but its support is limited to <a href="https://caniuse.com/#search=cross-fade">earlier specs and Webkit currently</a>.</p>
The Stroboscopic Effect: Illusions on the Web Part 32018-08-13T00:00:00Zhttps://danielcwilson.com/blog/2018/08/optical-fun-zoetrope/<p class="preamble">This is the third in an <a href="https://danielcwilson.com/tags/illusions">article series discussing different optical illusions & mechanical toys</a> and how we can recreate them on the web (and learn from them). Due to the nature of the methods discussed here, some animations will be fast, fill large screen space, and/or be shaky. All animations are paused by default.</p>
<p>In the 19th Century, many toys were created to take several static images and trick the mind into animating them by flashing elements between them. We will explore a few of these toys, recreate them on the web, and then look at some other related tricks we can do in the digital-only realm.</p>
<h3 id="the-general-principles" tabindex="-1">The General Principles <a class="direct-link" href="https://danielcwilson.com/blog/2018/08/optical-fun-zoetrope/#the-general-principles" aria-hidden="true">#</a></h3>
<p>All of these tricks in the physical world rely on a collection of images moving rapidly and some device that creates a <a href="https://en.wikipedia.org/wiki/Stroboscopic_effect">stroboscopic effect</a> to keep the mind from simply blurring the fast images. This effect could be achieved from a barrier with slits that alternates between showing you the images beneath and not, or in modern times with a strobe light. By coordinating the speed of the images with the timing of the stroboscopic effect, you can essentially keep focus in one area and the images will animate in a similar fashion to a film projector.</p>
<p>Perhaps the best example of this approach (at least that is still remembered in the 21st Century) is the Zoetrope.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/Px1AbfiQ_co?rel=0" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen=""></iframe>
<h3 id="exploring-the-zoetrope" tabindex="-1">Exploring the Zoetrope <a class="direct-link" href="https://danielcwilson.com/blog/2018/08/optical-fun-zoetrope/#exploring-the-zoetrope" aria-hidden="true">#</a></h3>
<p>The basic construction of a Zoetrope consists of a cylinder with a set number of slits, usually around an 1/8th of an inch. Additionally there are the same number of images on the inside of the cylinder. If you move the Zoetrope at an appropriately fast speed and focus on one section, you can see a looping animation with as many frames as there are images.</p>
<p>Without the outer cylinder, you will just see the images spinning around in a blur. The barrier breaks the images up much like a flipbook. Here we build this on the web using 3D Transforms (with some CSS Variables) where you can toggle the barrier on and off to see the difference.</p>
<p data-height="406" data-theme-id="dark" data-slug-hash="KBPLOg" data-default-tab="result" data-user="danwilson" data-pen-title="Zoetrope (Smiley)" data-preview="true" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/KBPLOg/">Zoetrope (Smiley)</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<h3 id="3d-zoetropes" tabindex="-1">3D Zoetropes <a class="direct-link" href="https://danielcwilson.com/blog/2018/08/optical-fun-zoetrope/#3d-zoetropes" aria-hidden="true">#</a></h3>
<p>In a similar vein, 3D Zoetropes often take images or sculptures and place them around a circle as well, but instead of a barrier cylinder to create the flipping effect, a strobe light is used. One of the more recent examples of this approach is with Toy Story.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/RjSxrVXsfVM?rel=0&start=80" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen=""></iframe>
<p>The timing of the strobe and the spin can be so precise that characters can stand perfectly in place if desired.</p>
<p>We can recreate this on the web as well, with an added bit of glitch due to pushing the limits on framerates. We first create a barrier div of solid black that covers the entire page and toggle its opacity from <code>1</code> to <code>0</code> as fast as possible. Then we spin our Zoetrope built via 3D Transforms to match the strobe. If we have twelve frames, and our strobe is in the <code>on</code> state for X milliseconds (and also in the <code>off</code> state for X milliseconds) we will want one full rotation to take <code>(12 × 2 × X)ms</code> so that the on and off states can be activated during each frame.</p>
<p data-height="314" data-theme-id="dark" data-slug-hash="479bb7b197fad5aefb333c3149d1b2e6" data-default-tab="css,result" data-user="danwilson" data-pen-title="3D Zoetrope Final" data-preview="true" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/479bb7b197fad5aefb333c3149d1b2e6/">3D Zoetrope Final</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<h3 id="the-human-eye-vs.-computers" tabindex="-1">The Human Eye vs. Computers <a class="direct-link" href="https://danielcwilson.com/blog/2018/08/optical-fun-zoetrope/#the-human-eye-vs.-computers" aria-hidden="true">#</a></h3>
<p>Tricking our eyes with the physical toys is a little different than we do it on a computer. In 2018, we are most likely getting at best 60 frames per second on the web with our animations, so we can get a frame every 16 2/3 milliseconds. The browser and the eye can work together and do its typical “blur things things that go fast” most of the time.</p>
<p>However, we can take our Zoetrope based in its 1860s roots and update it for the computer age by trying to match its rotation to the 60 frames per second ideal. So if we have a 24 frame animation, we can spin our Zoetrope a full turn (without its outer cylinder) at <code>24 × 16 2/3</code> milliseconds (which equals 400ms) and get a <a href="https://codepen.io/danwilson/pen/BPqYzK">similar, but clearer, animation effect</a>.</p>
<p>Even without the outer barrier, it might still shake a little or stutter, especially on lower powered devices… but that’s half the fun of animating on the web in the style of the 150 years ago.</p>
<p>This approach can be extended to other related moving picture toys like the <a href="https://en.wikipedia.org/wiki/Phenakistiscope">Phénakistiscope</a>. This was a flat circular toy that had images around the edge and slits in the middle of the circle. If you held the images towards a mirror and looked through the slits as you spin, you’d see a similar animation as our Zoetropes. But with our “spin it as fast you can” technique we can get rid of the slits and mirrors to <a href="https://codepen.io/danwilson/full/rrmyMv">spin the CSS Phénakistiscope circle around</a> every <code>16 2/3 × number of frames</code> milliseconds.</p>
<p>Or we can get rid of our needs for circles and spinning by simplifying and move left and right. If we align our images in a row, and animate a <code>translateX(-100%)</code> matching our 60 frames per second we get the same effect.</p>
<p data-height="265" data-theme-id="dark" data-slug-hash="yqywgJ" data-default-tab="css,result" data-user="danwilson" data-pen-title="Zoetrope Strip: 48 frames + 60fps" data-preview="true" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/yqywgJ/">Zoetrope Strip: 48 frames + 60fps</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<h3 id="an-aside:-but-what-about-the-steps()-timing-function" tabindex="-1">An Aside: But What about the <code>steps()</code> Timing Function? <a class="direct-link" href="https://danielcwilson.com/blog/2018/08/optical-fun-zoetrope/#an-aside:-but-what-about-the-steps()-timing-function" aria-hidden="true">#</a></h3>
<p>You got me… we didn’t need to take this as far as we did to create images that flip through a bunch of frames, because we can do this by using a <code>steps()</code> timing function in CSS (or <code>easing</code> property if you are in the Web Animations API world). And now we don’t necessarily have to max out our speed to get a smooth frame by frame animation.</p>
<p data-height="286" data-theme-id="dark" data-slug-hash="gjdNWv" data-default-tab="css,result" data-user="danwilson" data-pen-title="Zoetrope Strip: Steps()" data-preview="true" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/gjdNWv/">Zoetrope Strip: Steps()</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<h3 id="but...-can-we-spin-one-more-thing-before-we-conclude" tabindex="-1">But… Can We Spin One More Thing before We Conclude? <a class="direct-link" href="https://danielcwilson.com/blog/2018/08/optical-fun-zoetrope/#but...-can-we-spin-one-more-thing-before-we-conclude" aria-hidden="true">#</a></h3>
<p>Sure. A friend of mine once had a spinning top with a specific arrangement of arcs on its surface, and once it is spinning the eye sees complete circles. I made the following demo to reproduce the effect (to an extent), but I soon found out this effect is even more involved and can cause different people to see different colors in the circles. This toy goes by the name of <a href="https://en.wikipedia.org/wiki/Benham%27s_top">Benham’s Top</a>.</p>
<p data-height="265" data-theme-id="dark" data-slug-hash="rvjYbX" data-default-tab="css,result" data-user="danwilson" data-pen-title="Spinning Fast to Fill the Gaps" data-preview="true" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/rvjYbX/">Spinning Fast to Fill the Gaps</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<p>Adding the solid black half circle introduces the color effects for some people. Interestingly, reversing the spin reverses where the colors appear.</p>
<h3 id="the-limits-of-today" tabindex="-1">The Limits of Today <a class="direct-link" href="https://danielcwilson.com/blog/2018/08/optical-fun-zoetrope/#the-limits-of-today" aria-hidden="true">#</a></h3>
<p>Many people might see the limitation of today’s browsers and screens to animate at 60 frames per second as a problem. We always want more power, more speed, and more bandwidth working on the web, but sometimes the limitations give us new abilities and new ways to play.</p>
<p>And the limits of today are not necessarily the limitations of tomorrow.</p>
CSS Motion Path beyond the Big Three Properties2018-05-08T00:00:00Zhttps://danielcwilson.com/blog/2018/05/offset-and-beyond/<p>While still only in Chromium-based browsers and actively being drafted for its specification, CSS Motion Path has grown up a bit in its three years since Chrome 46 rolled out the first implementation.</p>
<p>I've previously documented the <a href="https://codepen.io/danwilson/post/css-motion-paths-2016">basics of the primary CSS Motion Path</a> use case via the main three properties — <code>offset-path</code> to define a path for an element to follow, <code>offset-distance</code> to position the element on that path, and <code>offset-rotate</code> to affect the direction the element faces.</p>
<p>There are additions to the spec since my last roundup (and even better, some features actually rolling out to Chrome), so assuming you are already familiar with the basics let’s dig in to the new functionality. To make sure you are seeing the latest, view this article and its demos in Chrome 66+ with Experimental Web Platform Features enabled in <code>chrome://flags</code>.</p>
<p data-height="312" data-theme-id="0" data-slug-hash="PQddxe" data-default-tab="result" data-user="danwilson" data-embed-version="2" data-pen-title="Banners in the Wind" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/PQddxe/">Banners in the Wind</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<h3 id="anchoring-the-element" tabindex="-1">Anchoring the element <a class="direct-link" href="https://danielcwilson.com/blog/2018/05/offset-and-beyond/#anchoring-the-element" aria-hidden="true">#</a></h3>
<p>By default, an element with a path will move as though the center of the element is connected to the path. We can change this location with the <code>offset-anchor</code> property. This accepts a <code><position></code>, so it takes values similar to <code>background-position</code> or <code>transform-origin</code>, with an <code>x</code> and a <code>y</code>, either as a numerical value or a keyword like <code>center</code>.</p>
<p data-height="377" data-theme-id="0" data-slug-hash="wJRmGz" data-default-tab="css,result" data-user="danwilson" data-embed-version="2" data-pen-title="Offset Path Anchor" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/wJRmGz/">Offset Path Anchor</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<h3 id="animating-the-path-itself" tabindex="-1">Animating the path itself <a class="direct-link" href="https://danielcwilson.com/blog/2018/05/offset-and-beyond/#animating-the-path-itself" aria-hidden="true">#</a></h3>
<p>A couple years ago, Chromium introduced support for the <code>d</code> property in CSS that takes a <code>path()</code> and maps directly to the value you would find in a <code>d</code> attribute inside an SVG <code>path</code> element. This allows you to change the definition of the path in CSS, and additionally supported animation if the browser can interpolate the values needed, as demonstrated by Chris Coyier.</p>
<p data-height="265" data-theme-id="0" data-slug-hash="NRwANp" data-default-tab="css,result" data-user="chriscoyier" data-embed-version="2" data-pen-title="Simple Path Examples" class="codepen">See the Pen <a href="https://codepen.io/chriscoyier/pen/NRwANp/">Simple Path Examples</a> by Chris Coyier (<a href="https://codepen.io/chriscoyier">@chriscoyier</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<p>The CSS Motion Path spec introduced similar interpolation logic for the <code>offset-path</code> property. Therefore, not only can we move an element along a path, we can change the path along which it moves.</p>
<p data-height="321" data-theme-id="0" data-slug-hash="vxQKvm" data-default-tab="css,result" data-user="danwilson" data-embed-version="2" data-pen-title="Animating offset-distance & offset-path (& d)" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/vxQKvm/">Animating offset-distance & offset-path (& d)</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<p>The white path in this example is in the SVG, being animated in CSS with a keyframe animation modifying the <code>d</code> property. The blue polygon is animating in two ways, starting with a more typical animation of its <code>offset-distance</code> from <code>0%</code> to <code>100%</code>. It also is animating the <code>offset-path</code> property itself, using the same two keyframes used in the SVG path’s <code>d</code> animation.</p>
<h3 id="rays-and-polar-coordinates" tabindex="-1">Rays and polar coordinates <a class="direct-link" href="https://danielcwilson.com/blog/2018/05/offset-and-beyond/#rays-and-polar-coordinates" aria-hidden="true">#</a></h3>
<p>The biggest change to the <a href="https://drafts.fxtf.org/motion-1/">CSS Motion Path spec</a> since its introduction was its combining with parts of thee CSS Round spec. In particular, the concept of polar coordinates was rolled into the <code>offset-path</code> property. This will be a pretty powerful option as outlined in the spec, but its current "behind a flag" version is currently only a small subset of the feature. As such, I will only touch on what is implemented now, as the full version will be easier to explain when it is implemented.</p>
<p>The key here is that <code>offset-path</code> now accepts a new <code>ray()</code> function which specifies an angle. This angle creates a line to position through polar coordinates from the center of a circle. Combined with an <code>offset-distance</code>, this angle will determine in which direction the element will move from the circle and how far.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.polar</span> <span class="token punctuation">{</span><br /> <span class="token property">offset-path</span><span class="token punctuation">:</span> <span class="token function">ray</span><span class="token punctuation">(</span>90deg<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property">offset-distance</span><span class="token punctuation">:</span> 100px<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>This will take our element and move it 100px to the right. Using 135 degrees would move it to the bottom right.</p>
<p>Since we can now animate both <code>offset-path</code> and <code>offset-distance</code> we can animate an element going around a circle’s edge and animate it going toward and away from the center.</p>
<p data-height="341" data-theme-id="0" data-slug-hash="PObxzg" data-default-tab="css,result" data-user="danwilson" data-embed-version="2" data-pen-title="CSS Motion Path with ray()" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/PObxzg/">CSS Motion Path with ray()</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<p>This is all in early stages. There will be a lot more to explore here once the full implementation lands. That is when we can talk about containing blocks, sides, and the fifth new CSS Motion Path property called <code>offset-position</code>.</p>
A Houdini Quickstart: registerProperty2018-02-12T00:00:00Zhttps://danielcwilson.com/blog/2018/02/houdini-quickstart/<p>Houdini has been discussed here and there for a few years now, always with the promise that it will open doors we have never had. Want to make a new way to do layout? Houdini. Want to create a new kind of gradient? Houdini.</p>
<p>In short, Houdini gives a developer building blocks in JavaScript to allow writing new kinds of CSS.</p>
<p>We have reached the point where this is more than just an idea or a spec. There are modules now in <a href="https://ishoudinireadyyet.com/">Blink browsers behind a flag</a> (as of this writing, this is the only way to try it). There are many code examples, but at first glance it all seems... complicated. Some of the key examples that resources point to look like a mysterious combination of <a href="https://github.com/GoogleChromeLabs/houdini-samples/blob/master/paint-worklet/ripple/paintworklet.js">CSS Variables, Canvas drawing, and JS in CSS</a>.</p>
<p>Luckily, there is a way to start exploring Houdini with one basic JavaScript method, called <code>CSS.registerProperty()</code>. We will look at Houdini in the context of CSS Custom Properties (CSS Variables) and animation.</p>
<p data-height="265" data-theme-id="dark" data-slug-hash="ddNYeV" data-default-tab="js,result" data-user="danwilson" data-embed-version="2" data-pen-title="Dance of the Houdini Hexagons" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/ddNYeV/">Dance of the Houdini Hexagons</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<h3 id="setting-the-stage:-an-intro-to-custom-properties" tabindex="-1">Setting the Stage: An Intro to Custom Properties <a class="direct-link" href="https://danielcwilson.com/blog/2018/02/houdini-quickstart/#setting-the-stage:-an-intro-to-custom-properties" aria-hidden="true">#</a></h3>
<p>I saw the power of Custom Properties with their <a href="https://danielcwilson.com/blog/2017/02/individual-transforms">support independent transform properties</a> in Firefox, Edge, Chrome, Opera, and Safari. They allows us, for example, to modify a <code>scale</code> without modifying an existing <code>rotate</code> on the same element, even though those are tied into a single <code>transform</code> property.</p>
<p>Custom Properties are powerful since they introduced a variable option to CSS natively for the first time, and they fit in with the cascade and inheritance nicely. But they, by design for the first spec, are not as powerful as they can be. To get the initial implementations in so many browsers semi-quickly, their power was limited. When you say <code>--my-prop: 2px</code>, the browser does not really know that is a length value. When it is used in the context of another property that expects a length (e.g. <code>transform: translateX(var(--my-prop))</code>), the browser then is able to parse it and treat it like a length.</p>
<p>Therefore, you cannot set a <code>transition</code> for <code>--my-prop</code> or modify its value in a <code>@keyframes</code> rule and have it animate smoothly. The browser does not have enough information to know what kind of syntax it is dealing with, or if it is even animatable. You <em>can</em>, however, still transition the property that it is used within if it is animatable (like the <code>transform</code> earlier).</p>
<h3 id="enter-css.registerproperty()-from-the-properties-and-values-api" tabindex="-1">Enter <code>CSS.registerProperty()</code> from the Properties and Values API <a class="direct-link" href="https://danielcwilson.com/blog/2018/02/houdini-quickstart/#enter-css.registerproperty()-from-the-properties-and-values-api" aria-hidden="true">#</a></h3>
<p>With the Properties and Values API spec (inside the larger Houdini endeavor) we can now tell the browser what to expect for each property.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">if</span> <span class="token punctuation">(</span>window<span class="token punctuation">.</span><span class="token constant">CSS</span> <span class="token operator">&&</span> <span class="token constant">CSS</span><span class="token punctuation">.</span>registerProperty<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token constant">CSS</span><span class="token punctuation">.</span><span class="token function">registerProperty</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br /> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'--my-prop'</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">syntax</span><span class="token operator">:</span> <span class="token string">'<length>'</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">initialValue</span><span class="token operator">:</span> <span class="token string">'0px'</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">inherits</span><span class="token operator">:</span> <span class="token boolean">false</span><br /> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>Here we can say that we want our CSS custom property named <code>--my-prop</code> to always have a valid <code><length></code> value. We also specify an initial value (for when no value is defined when we reference it via <code>var()</code>) and whether it inherits or not. To show the flexibility <code>inherits</code> provides, take the following CSS:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">ul, ol</span> <span class="token punctuation">{</span><br /> <span class="token property">--my-prop</span><span class="token punctuation">:</span> 20em<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token selector">li</span> <span class="token punctuation">{</span><br /> <span class="token property">width</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--my-prop<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>If <code>inherits</code> is <code>true</code> then the width of the list item will be <code>20em</code> since it can inherit its value from an ancestor. Otherwise, a <code>false</code> value will mean the list items will have a width of <code>0px</code> since that was the initial value defined in our JavaScript and there is no other value defined specifically on the <code>li</code> element.</p>
<p>By defining rules around how this property will behave we can have the browser reject syntaxes we do not want to support. Even more exciting (to me) is that we now have told the browser that a property is a <code>length</code> syntax (or <a href="https://www.w3.org/TR/css-properties-values-api-1/#supported-syntax-strings">angle, number, color, etc.</a> as defined in the spec) which the browser knows how to animate.</p>
<h3 id="fancy-transforms-as-an-example" tabindex="-1">Fancy Transforms as an example <a class="direct-link" href="https://danielcwilson.com/blog/2018/02/houdini-quickstart/#fancy-transforms-as-an-example" aria-hidden="true">#</a></h3>
<p data-height="265" data-theme-id="dark" data-slug-hash="OQmbmV" data-default-tab="css,result" data-user="danwilson" data-embed-version="2" data-pen-title="Animating CSS Variables (Houdini Basics)" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/OQmbmV/">Animating CSS Variables (Houdini Basics)</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<p>We register several properties in the JavaScript as angles, and then we give three nested elements each a <code>transform</code> that is composed of the the same custom properties in different variations of rotations. We can give them all the exact same <code>@keyframes</code>, but each will have a different animation since the custom properties combine into different <code>transform</code>s.</p>
<p>This extends to transitions, as well where you can specify different transitions for each of the transform functions that make up a single <code>transform</code> property.</p>
<p>But why stop there when you can even combine animations <em>and</em> transitions on a single <code>transform</code>. In this example, each element still has a <code>keyframe</code> animation, but on <code>body:hover</code> the middle element will do an additional rotation around the Z axis, smoothly performing its <code>transition</code> while the <code>animation</code> continues. The browser has all the informaiton it needs to interpolate the values thanks to the custom property’s syntax defined with <code>CSS.registerProperty()</code>.</p>
<p data-height="265" data-theme-id="dark" data-slug-hash="JpNbpe" data-default-tab="css,result" data-user="danwilson" data-embed-version="2" data-pen-title="Animating CSS Variables (Houdini Basics 2)" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/JpNbpe/">Animating CSS Variables (Houdini Basics 2)</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<h3 id="more-info" tabindex="-1">More Info <a class="direct-link" href="https://danielcwilson.com/blog/2018/02/houdini-quickstart/#more-info" aria-hidden="true">#</a></h3>
<p>Vincent De Oliveira has an <a href="https://lab.iamvdo.me/houdini/">excellent playground</a> that shows off Houdini at a larger scale, including the other APIs under the Houdini banner like Paint and Layout. Google also is putting the <a href="https://developers.google.com/web/updates/2018/01/paintapi">initial Paint API in Chrome stable</a> soon, with a solid introduction by Surma.</p>
<p>Enjoy.</p>
Barrier Grid Animation: Illusions on the Web Part 22018-02-07T00:00:00Zhttps://danielcwilson.com/blog/2018/02/optical-fun-barrier-grid/<p class="preamble">This is the second in an <a href="https://danielcwilson.com/tags/illusions">article series discussing different optical illusions & mechanical toys</a> and how we can recreate them on the web (and improve them). Due to the nature of this method, some animations shown here will be fast and fill large screen space. All animations are paused by default.</p>
<p>In various forms over the years, I have seen a technique to create animation in books or other non-digital and non-video forms. They go by many different names (Kinegrams, Scanimation®, stereographs), but for this discussion we will use the term “<a href="https://en.wikipedia.org/wiki/Barrier_grid_animation_and_stereography">Barrier Grid Animation</a>” as it describes the main shared component to create the illusion of motion.</p>
<p data-height="285" data-theme-id="32298" data-slug-hash="NyNgjN" data-default-tab="result" data-user="danwilson" data-embed-version="2" data-pen-title="Illusion of Motion Basic" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/NyNgjN/">Illusion of Motion Basic</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<p>In the non-digital world, this consists of a transparent sheet/cel with evenly spaced black lines on top of a second layer consisting of a seemingly chopped image. While not required, most of the time we are talking about vertical lines, so that is what we will assume.</p>
<p data-height="219" data-theme-id="32298" data-slug-hash="ddXOQZ" data-default-tab="result" data-user="danwilson" data-embed-version="2" data-pen-title="Illusion of Motion Split" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/ddXOQZ/">Illusion of Motion Split</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<p>With just these two physical elements you can create several frames of animation. By only moving the topmost layer the underlying collection of seemingly random lines take shape and animate.</p>
<h3 id="constructing-the-layers" tabindex="-1">Constructing the Layers <a class="direct-link" href="https://danielcwilson.com/blog/2018/02/optical-fun-barrier-grid/#constructing-the-layers" aria-hidden="true">#</a></h3>
<p>Both layers follow a pattern based on the width of a bar. For simplifying the math, we will use <code>1px</code> as our base unit. Our first example had five frames of a pink ball moving around. For such an animation, our top layer (the barrier) should consist of a <code>1px</code> wide transparent bar followed by <code>4px</code> of a black bar, repeated.</p>
<p>The bottom layer (consisting of the animation's frames) will be <code>1px</code> wide of the first frame, followed by <code>1px</code> of the second frame, etc. This also is repeated, so when our barrier grid is overlaid the same frame will be visible through the small transparent bar, while the other four are covered. The following example demonstrates this (zoomed in for clarification) with each color representing a different frame.</p>
<p data-height="240" data-theme-id="32298" data-slug-hash="jZrWRv" data-default-tab="result" data-user="danwilson" data-embed-version="2" data-pen-title="Illusion of Motion Zoom" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/jZrWRv/">Illusion of Motion Zoom</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<p>As we move the top layer left and right we will see effectively one frame at a time in sequence. We are blocking out a majority of each image, but our brain will do its best to fill in the missing pieces as the animation progresses by moving the top layer.</p>
<p>We want a pattern for our image where every fifth pixel is from frame 1, every fifth pixel plus one shows frame 2, etc. We will take the following markup where each unnamed div represents a frame (though the <code>div.barrier</code> could also be implemented as a pseudoelement):</p>
<pre class="language-markup"><code class="language-markup"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>main</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span><br /> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>cover<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span><br /><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>main</span><span class="token punctuation">></span></span></code></pre>
<p>The cover boils down to a linear gradient to the right with <code>1px</code> transparency and <code>4px</code> black. I use CSS Variables to adapt it as I go, such as if I want to quickly see what happens if I change the base unit to <code>2px</code>.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.cover</span> <span class="token punctuation">{</span><br /> <span class="token property">background</span><span class="token punctuation">:</span><br /> <span class="token function">linear-gradient</span><span class="token punctuation">(</span>to right<span class="token punctuation">,</span><br /> transparent 0px<span class="token punctuation">,</span><br /> transparent <span class="token function">var</span><span class="token punctuation">(</span>--pixel<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token comment">/* 1px */</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--cover<span class="token punctuation">)</span> <span class="token function">var</span><span class="token punctuation">(</span>--pixel<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--cover<span class="token punctuation">)</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--pixel<span class="token punctuation">)</span> * 5<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 5px = 1 + 4 */</span><br /> <span class="token property">background-size</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--pixel<span class="token punctuation">)</span> * 5<span class="token punctuation">)</span> 100%<span class="token punctuation">;</span> <span class="token comment">/* repeat horizontally */</span><br /><span class="token punctuation">}</span><br /><span class="token selector">:root</span> <span class="token punctuation">{</span><br /> <span class="token property">--pixel</span><span class="token punctuation">:</span> 1px<span class="token punctuation">;</span><br /> <span class="token property">--cover</span><span class="token punctuation">:</span> black<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>The hardest part of setting up the barrier grid animation is creating the base image with the chopped frames. However, with blend modes and repeating linear gradients we can accomplish it with CSS.</p>
<h3 id="chopping-the-frames" tabindex="-1">Chopping the Frames <a class="direct-link" href="https://danielcwilson.com/blog/2018/02/optical-fun-barrier-grid/#chopping-the-frames" aria-hidden="true">#</a></h3>
<p>We can take an image and prep it to be a frame in our animation by using multiple backgrounds — the topmost background being a repeating linear gradient on top of the image we want to chop.</p>
<p data-height="240" data-theme-id="light" data-slug-hash="af14d0c8d32ba4edd02a3a83768bc704" data-default-tab="css,result" data-user="danwilson" data-embed-version="2" data-pen-title="Repeating Linear Gradient Over an Image" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/af14d0c8d32ba4edd02a3a83768bc704/">Repeating Linear Gradient Over an Image</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<p>To get our second frame we apply the same gradient, but we adjust the <code>background-position</code>. You can use a preprocessor to adjust this offset without repeating code, though we are only dealing with a few frames so the resulting CSS would be:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">div</span> <span class="token punctuation">{</span><br /> <span class="token property">background-position</span><span class="token punctuation">:</span> 0px 0px<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token selector">div:nth-of-type(2)</span> <span class="token punctuation">{</span><br /> <span class="token property">background-position-x</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--pixel<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token selector">div:nth-of-type(3)</span> <span class="token punctuation">{</span><br /> <span class="token property">background-position-x</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--pixel<span class="token punctuation">)</span> * 2<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token selector">div:nth-of-type(4)</span> <span class="token punctuation">{</span><br /> <span class="token property">background-position-x</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--pixel<span class="token punctuation">)</span> * 3<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token selector">div:nth-of-type(5)</span> <span class="token punctuation">{</span><br /> <span class="token property">background-position-x</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--pixel<span class="token punctuation">)</span> * 4<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>We need to stack our frames over each other so we can position them all as <code>absolute</code>, but we will only see the last frame at this point since we do not have anything with transparency on our frames. Luckily we chose <code>white</code> as our gradient color which will pair nicely with a <code>mix-blend-mode: multiply</code> setting.</p>
<p data-height="300" data-theme-id="32298" data-slug-hash="e0305c9dffc055758d2ac16535d2d453" data-default-tab="result" data-user="danwilson" data-embed-version="2" data-pen-title="Repeating Linear Gradient Over an Image with Transparency" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/e0305c9dffc055758d2ac16535d2d453/">Repeating Linear Gradient Over an Image with Transparency</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<p>A whole series could be written on blend modes, or even simply on multiplying colors. The quick-ish version is that for multiple overlapping elements, we look at each pixel and perform a function to blend the colors on each layer at that pixel. More specifically, the functions happen on each of the three RGB channel values, mapping to a range of <code>0</code> to <code>1</code> (so a value of <code>255</code> in a channel would equal <code>1</code>). With multiplication, whenever we have any color multiplied by black (with an R,G,B of <code>0,0,0</code>), the resulting color will always be black. This comes from standard mathematics where multiplying any number by zero will result in zero.</p>
<code>
black x red<br />
rgb(0,0,0) x rgb(1,0,0)<br />
rgb(0 x 1, 0 x 0, 0 x 0) = rgb(0,0,0);<br />
</code>
<p>Similarly, multiplying by white is like multiplying a number by one. Any number times one is equal to that same number, so any color multiplied by white will equal the same color.</p>
<code>
white x red<br />
rgb(1,1,1) x rgb(1,0,0)<br />
rgb(1 x 1, 1 x 0, 1 x 0) = rgb(1,0,0);<br />
</code>
<p>With the math out of the way, we can see how applying the blend mode of <code>multiply</code> can let the white bars of each frame effectively become transparent by letting anything that is not white be visible. Since each frame is offset by <code>1px</code> all frames are seen at once and our image is officially “chopped.”</p>
<p data-height="360" data-theme-id="32298" data-slug-hash="WMGYde" data-default-tab="result" data-user="danwilson" data-embed-version="2" data-pen-title="Illusion of Motion (How To Animation)" data-preview="true" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/WMGYde/">Illusion of Motion (How To Animation)</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<h3 id="bringing-it-all-together" tabindex="-1">Bringing it all together <a class="direct-link" href="https://danielcwilson.com/blog/2018/02/optical-fun-barrier-grid/#bringing-it-all-together" aria-hidden="true">#</a></h3>
<p>With the barrier constructed and the underlying animation images chopped, we are able to create our animation by moving our topmost layer horizontally. You can either do this with a fixed animation, tie into pointer events where you must drag the barrier layer, or tying it into the accelerometer to get that real old school magical vibe. I show these last two techniques in this full demo (for iOS or other devices that do not allow iframes to access accelerometer, you can <a href="https://s.codepen.io/danwilson/debug/GmwjYp">view the direct demo</a>)</p>
<p data-height="362" data-theme-id="light" data-slug-hash="GmwjYp" data-default-tab="css,result" data-user="danwilson" data-embed-version="2" data-pen-title="Illusion of Motion" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/GmwjYp/">Illusion of Motion</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<h3 id="are-there-better-ways-to-achieve-animation-on-the-web" tabindex="-1">Are there better ways to achieve animation on the web? <a class="direct-link" href="https://danielcwilson.com/blog/2018/02/optical-fun-barrier-grid/#are-there-better-ways-to-achieve-animation-on-the-web" aria-hidden="true">#</a></h3>
<p>No.</p>
<p>Okay, fine. This technique grew out of putting animation into books and small toy packages. We have actual animation in CSS where the browser can fill in the frames for us, and we have the easing option <code>steps()</code> (with <a href="https://github.com/w3c/csswg-drafts/issues/1680">future improvements coming</a>) for cases where we want to specify frames more granularly.</p>
<p>But... this was at least fun, right?</p>
RSS Club for All2018-02-03T00:00:00Zhttps://danielcwilson.com/blog/2018/02/rss-club/<p>I've used RSS for years, but had shied away from it after the disappearance of iGoogle (that's right, I never relied on Google Reader, instead just the dashboard view Google had for a while) as I didn't have a good replacement. Well, really it was just I didn't know what a good replacement was.</p>
<p>But people who know me know that I like reading and hyperclicking on the web. Big Social Media is more of a get in and get out type place with regard to links (or more likely skimming a headline, pressing a like or angry face, sharing it with a highly-likely-to-be-irrelevant opinion of the article you did not read, and scrolling to the next headline).</p>
<p>As such, the days of RSS, blogrolls, and webrings still have a special place in my heart. While not perfect, I've wanted for a while to incorporate those ideas into my site (and side projects). At about the same time as I was refocusing on RSS and newsletters, I happened upon a post on <a href="https://daverupert.com/">Dave Rupert</a>'s <a href="http://daverupert.com/atom.xml">RSS feed</a> about a so called RSS Club. An idea to write posts specfically for those who subscribe to your RSS, and connect together unofficially through these feeds. He proposes three rules:</p>
<ul>
<li>1st rule of RSS Club is “Don’t Talk About RSS Club”.</li>
<li>2nd rule of RSS Club is “Don’t Share on Social Media”.</li>
<li>3rd rule of RSS Club is “Provide Value”.</li>
</ul>
<p>Love it.</p>
<p>I have a Jekyll setup similar to Dave, and since so he outlined his implementation details it was a low barrier for me to join. I'm making an additional change to my article templates (Dave still gives these special posts a URL, just only links to them through RSS). In an effort to make them a little more secretive, I'm going to minimize the searchability with a robots <code>meta</code> tag in the <code>head</code>:</p>
<pre class="language-html"><code class="language-html">{% raw %}<br />{% if page.rssonly %}<br /><br /><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>robots<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>none<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br />{% endif %}<br />{% endraw %}</code></pre>
<p><em>This is the best practice way to do this now right? Instead of <code>robots.txt</code>?</em></p>
<p>I have a few special posts that I might post here in advance for a week or two before releasing at large. I also have been sitting on a prototype for my sequel to <a href="http://adeptmentalmath.com/palindromes">Path to Palindromes</a> for almost two years that I will probably talk about here to (maybe?) inspire me to finish it out. This might also be where I talk about how I'm adopting IndieWeb principles (and how that fits in with my Jekyll setup) and the hiccups I encounter. Not sure, but it's fun to have something new to try...</p>
The Red Reveal: Illusions on the Web Part 12018-02-01T00:00:00Zhttps://danielcwilson.com/blog/2018/02/optical-fun-red-reveal/<p class="preamble">This is the first in an <a href="https://danielcwilson.com/tags/illusions">article series discussing different optical illusions & mechanical toys</a> and how we can recreate them on the web (and improve them).</p>
<p>Growing up, my family played a lot of board games. Several games such as Outburst, Password, and Clue Jr. included something that amazed me at the time — a red lens and cards with some light blue text that was obscured by a myriad of red lines. When you put the red lens over the card, the text would magically appear.</p>
<p data-height="306" data-theme-id="32298" data-slug-hash="ZrGBVx" data-default-tab="result" data-user="danwilson" data-embed-version="2" data-pen-title="Drag to Make the Red Squiggles Disappear" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/ZrGBVx/">Drag to Make the Red Squiggles Disappear</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<p>I spent twenty or so years without thinking about these again until I was watching an episode of Tumble Leaf where they discover hidden messages. This sent me on a whirlwind of finding related products and recreating the effect on the web, since most of my life is centered around recreating and extending things my kids like.</p>
<h3 id="what-is-happening-with-the-red-reveal" tabindex="-1">What is Happening with the Red Reveal <a class="direct-link" href="https://danielcwilson.com/blog/2018/02/optical-fun-red-reveal/#what-is-happening-with-the-red-reveal" aria-hidden="true">#</a></h3>
<p>This was harder to duckduckgo than I expected because I didn't know the concept's name. Some message boards on board game fan sites led me to the name "red reveal," and that is what I am using for this article.</p>
<p>The basic effect is that you have an image or text on the base that is a cyan (let's say <code>hsl(180,100%,50%)</code>). This will be the hidden content. We then add a mask that is red (180deg around the color wheel at <code>hsl(0,100%,50%)</code>) over it, either with other text, red squiggles, a mix of lines, or other images. Then look at the card through a red lens (or cellophane — anything that is close to a true red and not opaque). Just like magic the cyan is now highly visible and the red mask is effectively removed.</p>
<p>We can recreate this on the web with three layers and use of blend modes, opacity, and repeating linear gradients, and custom properties.</p>
<p>On our bottom layer, let's add text in cyan (or an image with cyan outlines). I also set an opacity between .25 and .5 so it's harder to see against the white background. We then add a second layer with multiple repeating linear gradients that create a stitched pattern that make it all the harder to see the cyan message.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.hide-the-message</span> <span class="token punctuation">{</span><br /> <span class="token property">--reveal</span><span class="token punctuation">:</span> <span class="token function">hsl</span><span class="token punctuation">(</span>0<span class="token punctuation">,</span> 100%<span class="token punctuation">,</span> 50%<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property">--start</span><span class="token punctuation">:</span> 5px<span class="token punctuation">;</span><br /> <span class="token property">--end</span><span class="token punctuation">:</span> 7px<span class="token punctuation">;</span><br /> <span class="token property">background</span><span class="token punctuation">:</span><br /> <span class="token function">repeating-linear-gradient</span><span class="token punctuation">(</span>155deg<span class="token punctuation">,</span><br /> transparent 0<span class="token punctuation">,</span> transparent <span class="token function">var</span><span class="token punctuation">(</span>--start<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--reveal<span class="token punctuation">)</span> <span class="token function">var</span><span class="token punctuation">(</span>--start<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--reveal<span class="token punctuation">)</span> <span class="token function">var</span><span class="token punctuation">(</span>--end<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">repeating-linear-gradient</span><span class="token punctuation">(</span>115deg<span class="token punctuation">,</span><br /> transparent 0<span class="token punctuation">,</span> transparent <span class="token function">var</span><span class="token punctuation">(</span>--start<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--reveal<span class="token punctuation">)</span> <span class="token function">var</span><span class="token punctuation">(</span>--start<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--reveal<span class="token punctuation">)</span> <span class="token function">var</span><span class="token punctuation">(</span>--end<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">repeating-linear-gradient</span><span class="token punctuation">(</span>45deg<span class="token punctuation">,</span><br /> transparent 0<span class="token punctuation">,</span> transparent <span class="token function">var</span><span class="token punctuation">(</span>--start<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--reveal<span class="token punctuation">)</span> <span class="token function">var</span><span class="token punctuation">(</span>--start<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--reveal<span class="token punctuation">)</span> <span class="token function">var</span><span class="token punctuation">(</span>--end<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>It's the third layer where we undo the obscuring lines and reveal the message. The lens is a circle with the same red as a background, with a multiply blend mode. The red lens now can effectively hide the red lines. The multiply blending makes the cyan combine with the red to create black (though, since an opacity was applied to the cyan it will not be fully black).</p>
<p data-height="306" data-theme-id="32298" data-slug-hash="b0bda0b7e1822f9681bf2e9388468614" data-default-tab="result" data-user="danwilson" data-embed-version="2" data-pen-title="Multiply Mix Blend Example" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/b0bda0b7e1822f9681bf2e9388468614/">Multiply Mix Blend Example</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<p>Add JavaScript to make the element move as your mouse or finger moves with custom properties, and we have a complete interactive recreation.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> lens <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'lens'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">function</span> <span class="token function">move</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">if</span> <span class="token punctuation">(</span>e<span class="token punctuation">.</span>clientX <span class="token operator">||</span> e<span class="token punctuation">.</span>touches<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">var</span> x <span class="token operator">=</span> <span class="token punctuation">(</span>e<span class="token punctuation">.</span>clientX <span class="token operator">||</span> e<span class="token punctuation">.</span>touches<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>clientX<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">var</span> y <span class="token operator">=</span> <span class="token punctuation">(</span>e<span class="token punctuation">.</span>clientY <span class="token operator">||</span> e<span class="token punctuation">.</span>touches<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>clientY<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /> lens<span class="token punctuation">.</span>style<span class="token punctuation">.</span><span class="token function">setProperty</span><span class="token punctuation">(</span><span class="token string">'--x'</span><span class="token punctuation">,</span> x <span class="token operator">+</span><span class="token string">'px'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> lens<span class="token punctuation">.</span>style<span class="token punctuation">.</span><span class="token function">setProperty</span><span class="token punctuation">(</span><span class="token string">'--y'</span><span class="token punctuation">,</span> y <span class="token operator">+</span><span class="token string">'px'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p data-height="306" data-theme-id="light" data-slug-hash="XVBLpp" data-default-tab="result" data-user="danwilson" data-embed-version="2" data-pen-title="Drag to Reveal the Image" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/XVBLpp/">Drag to Reveal the Image</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<h3 id="focusing-on-the-lens-aspect" tabindex="-1">Focusing on the Lens Aspect <a class="direct-link" href="https://danielcwilson.com/blog/2018/02/optical-fun-red-reveal/#focusing-on-the-lens-aspect" aria-hidden="true">#</a></h3>
<video autoplay="" muted="" playsinline="" loop="">
<source src="https://danielcwilson.com/img/posts/2018/lens1.webm" />
<source src="https://danielcwilson.com/img/posts/2018/lens1.mp4" />
</video>
<p>As I learned more about this optical trick, I happened upon a Wide Eyed Editions book called <a href="https://www.quartoknows.com/books/9781847808875/Illuminature.html?direct=1">Illuminature</a> that takes it up a level by printing three images on top of each other in different colors. Then by using three different lenses (red, green, and blue) you are able to largely separate each out. The other two images become the mask for the image that matches the lens you choose.</p>
<p>It is a beautiful book without the lenses, but it’s especially fun to explore and separate with the lenses. The provided lenses are small, and for such a large book, I felt it would be better to have a larger lens to look through.</p>
<video autoplay="" muted="" playsinline="" loop="">
<source src="https://danielcwilson.com/img/posts/2018/lens2.webm" />
<source src="https://danielcwilson.com/img/posts/2018/lens2.mp4" />
</video>
<p>I also had been meaning to learn about streaming video. So taking what I learned with having a red circle with a <code>mix-blend-mode: multiply</code> to get those cyan markings to darken, I set up a red fullscreen element on top of a <code>video</code> element. When you allow access to the camera (which prefers the camera that is facing away from a user when on a phone) it will show underneath the blending element. Toggle to green or blue to see the other images in the book with ease.</p>
<pre class="language-js"><code class="language-js">navigator<span class="token punctuation">.</span>mediaDevices<span class="token punctuation">.</span><span class="token function">getUserMedia</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br /> <span class="token literal-property property">audio</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">video</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">facingMode</span><span class="token operator">:</span> <span class="token string">'environment'</span> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">stream</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">var</span> video <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'video'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> video<span class="token punctuation">.</span>srcObject <span class="token operator">=</span> stream<span class="token punctuation">;</span><br /> video<span class="token punctuation">.</span><span class="token function-variable function">onloadedmetadata</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> video<span class="token punctuation">.</span><span class="token function">play</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token parameter">err</span> <span class="token operator">=></span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'error'</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>You can view the <a href="https://codepen.io/danwilson/pen/zpZPJm">demo on CodePen</a> (some platforms restrict camera access from iframes, like iOS, so you can also <a href="https://s.codepen.io/danwilson/debug/zpZPJm">view the direct example</a> to try it on those devices)</p>
<p>It works fairly well, at least on par with the provided lenses.</p>
Personal Goals and Guidelines for Technology: 2018 Edition2018-01-18T00:00:00Zhttps://danielcwilson.com/blog/2018/01/year-2018/<p>I have written this post about twenty times over, but it keeps turning into a rant against notifications, social media, digital assistants, and Blue Bell ice cream.</p>
<p>So instead of getting into the "why" (for now), I am going to simply document some goals I have for my site and guidelines for how I approach technology in general... in list form, since prose kept becoming a sixty paragraph ramble.</p>
<h3 id="my-site" tabindex="-1">My Site <a class="direct-link" href="https://danielcwilson.com/blog/2018/01/year-2018/#my-site" aria-hidden="true">#</a></h3>
<ol>
<li>Allow me to log in with my site, with <a href="https://indieweb.org/IndieAuth">IndieAuth</a> by March</li>
<li>Implement <a href="https://webmention.net/">webmentions</a> by April</li>
<li>Create a way to post short notes to my site, and syndicate to <a href="https://twitter.com/dancwilson">Twitter</a>, <a href="https://mastodon.social/@danwilson">Mastodon</a>, etc. by May</li>
<li>Post an article at least once a month, adding more general thoughts on technology and beyond in addition to the typical technical articles</li>
<li>Rebuild Projects page to show selected client work and CodePens instead of older hybrid apps that do not actually reflect my current priorities/strengths by February</li>
</ol>
<h3 id="general-personal-technology-guidelines" tabindex="-1">General Personal Technology Guidelines <a class="direct-link" href="https://danielcwilson.com/blog/2018/01/year-2018/#general-personal-technology-guidelines" aria-hidden="true">#</a></h3>
<p>In no particular order:</p>
<ol>
<li>Don’t access Facebook at all on my phone, even the browser. This is admittedly easier for me to do because I removed the Facebook app three years ago and never got tied into Facebook Messenger.</li>
<li>Keep Twitter app off my phone. Limit usage to desktop-only.</li>
<li>Do not allow notifications on anything but texts and calls on my phone.</li>
<li>Provide a look of complete and total disdain and/or sadness to every person who looks at their Apple Watch during a one on one conversation with me and then asks me to repeat what I was saying during the last 20 seconds of our one on one conversation.</li>
<li>Don’t atually do the previous guideline, but do be honest with people when they are effectively wasting my time because they got a notification that their next meeting is still at noon.</li>
<li>Go all in on RSS, and create a system that allows me to read the previous day’s news and web articles as a morning or evening newspaper/digest.</li>
<li>Be vocal in my web presence about issues that are important to me. I don’t have the biggest online presence, but it is still a platform I can use to speak out against hate, bigotry, and inequality.</li>
<li>Unplug all the Alexas and Google Homes in the office’s meeting rooms when I enter them... because why are they needed in there... or at all?</li>
<li>Do not use my phone in lines, at restaurant tables, or any place where I am doing it just because I am <a href="https://www.wnyc.org/series/bored-and-brilliant">"bored"</a></li>
</ol>
<h3 id="but-why" tabindex="-1">But why? <a class="direct-link" href="https://danielcwilson.com/blog/2018/01/year-2018/#but-why" aria-hidden="true">#</a></h3>
<p>I might dive into some specifics of my guidelines in the future (a lot of people question me on my approach to notification and Facebook in particular), but for now the overall reason is I enjoy simplicity. I get no joy out of scrolling through Facebook, for example. I’d much rather subscribe to a couple newspapers and donate to public radio and television and focus on their content. But even then, on my own time and not just to kill time.</p>
Additive Animation with the Web Animations API2018-01-02T00:00:00Zhttps://danielcwilson.com/blog/2018/01/additive-animation/<p>On CSS-Tricks: I discuss <a href="https://css-tricks.com/additive-animation-web-animations-api/">some of the newly implemented parts</a> of the Web Animations API Level 1 spec that allow us to modify currently running animations. These are the pieces that will really distinguish the API from the CSS animations we know and love... coming soon to a browser near you.</p>
<p><a href="https://css-tricks.com/additive-animation-web-animations-api/">View Article on CSS-Tricks →</a></p>
3 Ways to Use Independent Transform Properties2017-10-31T00:00:00Zhttps://danielcwilson.com/blog/2017/10/all-the-transform-ways/<p>I figure there are three main ways we can break out the individual transform functions (such as <code>translate</code> and <code>scale</code>) from the <code>transform</code> property without a library. The ability to set a new <code>rotate</code> without it affecting a previously set <code>scale</code>, for example, has long been desired by web developers. We’ll take a look at the pros and cons of each approach.</p>
<p>These pros and cons will be centered around each approach’s ability to support the following:</p>
<ol>
<li>Can we do any number of functions (multiple <code>rotate</code>s, multiple <code>scale</code>s, etc.)?</li>
<li>Can we specify the order (e.g. <code>scale</code> then <code>translate</code> gives a <a href="https://codepen.io/danwilson/pen/RjNZOW/">different end result</a> than <code>translate</code> then <code>scale</code>)?</li>
<li>Can they be transitioned (via <code>transition</code>)?</li>
<li>Can they be animated (via CSS Animations/<code>keyframes</code> or the Web Animations API)?</li>
</ol>
<p>To see why the first two points matter, play around with the following pen by reordering the transform functions and adding more.</p>
<p data-height="265" data-theme-id="0" data-slug-hash="eEYdgo" data-default-tab="js,result" data-user="danwilson" data-embed-version="2" data-pen-title="Visual Reference: Transform Coordinate Systems" data-editable="true" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/eEYdgo/">Visual Reference: Transform Coordinate Systems</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<h3 id="1-actual-independent-properties" tabindex="-1">#1 Actual Independent Properties <a class="direct-link" href="https://danielcwilson.com/blog/2017/10/all-the-transform-ways/#1-actual-independent-properties" aria-hidden="true">#</a></h3>
<p>Defined in the in-progress <a href="https://drafts.csswg.org/css-transforms-2/">CSS Transforms Level 2 specification</a> (and in Chrome behind the Experimental Web Platform Features flag), <code>translate</code>, <code>scale</code>, and <code>rotate</code> become their own properties. They can be handled individually, and therefore each can be animated and transitioned separately, too.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.independent-properties</span> <span class="token punctuation">{</span><br /> <span class="token property">translate</span><span class="token punctuation">:</span> 40px 10vmin<span class="token punctuation">;</span> <span class="token comment">/* X Y */</span><br /> <span class="token property">rotate</span><span class="token punctuation">:</span> 45deg<span class="token punctuation">;</span><br /> <span class="token property">scale</span><span class="token punctuation">:</span> .9 .9<span class="token punctuation">;</span> <span class="token comment">/* specify both X and Y */</span><br /><span class="token punctuation">}</span><br /><span class="token selector">.one-transform</span> <span class="token punctuation">{</span><br /> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translate</span><span class="token punctuation">(</span>40px<span class="token punctuation">,</span> 10vmin<span class="token punctuation">)</span> <span class="token function">rotate</span><span class="token punctuation">(</span>45deg<span class="token punctuation">)</span> <span class="token function">scale</span><span class="token punctuation">(</span>.9<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>The two rulesets have equivalent transformations. Now whenever we want to modify the transform — via classes or directly in JavaScript, for example — we can change only the desired property:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.independent-properties:hover</span> <span class="token punctuation">{</span><br /><span class="token property">rotate</span><span class="token punctuation">:</span> 225deg<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token selector">.one-transform:hover</span> <span class="token punctuation">{</span><br /> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translate</span><span class="token punctuation">(</span>40px<span class="token punctuation">,</span> 10vmin<span class="token punctuation">)</span> <span class="token function">rotate</span><span class="token punctuation">(</span>225deg<span class="token punctuation">)</span> <span class="token function">scale</span><span class="token punctuation">(</span>.9<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>You can transition and animate each individually as well, so for example you can specify different easings and durations for your <code>translate</code> than your <code>rotate</code>.</p>
<p><em>Pros</em></p>
<ul>
<li>Straightforward syntax</li>
<li>Can be transitioned and animated independently</li>
</ul>
<p><em>Cons</em></p>
<ul>
<li>Skew function is not represented</li>
<li>Can only do <a href="https://drafts.csswg.org/css-transforms-2/#individual-transforms">one function</a> per axis for each property... if you need to do multiple transformations you must use the <code>transform</code> property</li>
<li>Always <a href="https://drafts.csswg.org/css-transforms-2/#ctm">applied in the order</a>: <code>translate</code>, <code>rotate</code>, <code>scale</code>... if you need a different order you must go back to the <code>transform</code> property</li>
<li>Only in Blink browsers with flag enabled as of this writing.</li>
</ul>
<p>To be fair, the order that these individual properties are applied is a very common order for people to use, and multiple transformations are rarer, too. They still are a key difference with the <code>transform</code> property which gives a lot more power.</p>
<h3 id="2-custom-properties" tabindex="-1">#2 Custom Properties <a class="direct-link" href="https://danielcwilson.com/blog/2017/10/all-the-transform-ways/#2-custom-properties" aria-hidden="true">#</a></h3>
<p>I discovered the possibilities of mixing <a href="https://danielcwilson.com/blog/2017/02/individual-transforms/">custom properties with the <code>transform</code> property</a> earlier this year, and well... <a href="https://danielcwilson.com/blog/2017/06/dynamic-css-variables/">I’m still excited about them</a>. I’ll summarize the process here, but please check out the <a href="https://danielcwilson.com/blog/2017/02/individual-transforms/">original article for more details</a>.</p>
<p>The idea here is that we set up the standard <code>transform</code> property as we always have with every transformation we want to eventually apply using custom properties (which are supported in Firefox, Edge, Safari, Chrome, and Opera).</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.using-custom-properties</span> <span class="token punctuation">{</span><br /> <span class="token property">--translate-x</span><span class="token punctuation">:</span> 40px<span class="token punctuation">;</span><br /> <span class="token property">--translate-y</span><span class="token punctuation">:</span> 10vmin<span class="token punctuation">;</span><br /> <span class="token property">--rotate</span><span class="token punctuation">:</span> 45deg<span class="token punctuation">;</span><br /> <span class="token property">--scale</span><span class="token punctuation">:</span> .9<span class="token punctuation">;</span><br /><br /> <span class="token property">transform</span><span class="token punctuation">:</span><br /> <span class="token function">translateX</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--translate-x<span class="token punctuation">,</span> 0<span class="token punctuation">)</span><span class="token punctuation">)</span><br /> <span class="token function">translateY</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--translate-y<span class="token punctuation">,</span> 0<span class="token punctuation">)</span><span class="token punctuation">)</span><br /> <span class="token function">rotate</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--rotate<span class="token punctuation">,</span> 0deg<span class="token punctuation">)</span><span class="token punctuation">)</span><br /> <span class="token function">scale</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--scale<span class="token punctuation">,</span> 1<span class="token punctuation">)</span><span class="token punctuation">)</span><br /> <span class="token function">translateX</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--end-translate-x<span class="token punctuation">,</span> 0<span class="token punctuation">)</span><span class="token punctuation">)</span><br /><span class="token punctuation">}</span><br /><span class="token selector">.using-custom-properties.changed</span> <span class="token punctuation">{</span><br /> <span class="token property">--end-translate-x</span><span class="token punctuation">:</span> 5px<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>Now we can specify the order of our transformations, and we can do as many transformations as we want, since we are using our old friend <code>transform</code>.</p>
<p>We can even do transitions on the <code>transform</code> and any changes to one of the custom properties will trigger the transition. So in our example we could set a <code>transition: transform 200ms ease-in-out</code> in our rule and when the <code>changed</code> class is added we will smoothly move to our new location. The caveat here is that it is specifically a transition on the single <code>transform</code> property so your translation, for example, cannot have a different duration, easing, or delay than your scale.</p>
<p>Here is an example showing this approach on a button with multiple states. It also shows the first approach if you are in an enabled browser so you can compare them.</p>
<p data-height="254" data-theme-id="0" data-slug-hash="PJPbZx" data-default-tab="result" data-user="danwilson" data-embed-version="2" data-pen-title="Button Example: CSS Dev Conf" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/PJPbZx/">Button Example: CSS Dev Conf</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<p><em>Pros</em></p>
<ul>
<li>Any number of transforms allowed</li>
<li>We can use any order we want</li>
<li>Transitions</li>
<li>Supported anywhere custom properties are (Apple, Microsoft, Mozilla, Google, Opera all have them)</li>
</ul>
<p><em>Cons</em></p>
<ul>
<li>More verbose</li>
<li>Need to account for all potential transformations up front</li>
<li>Keyframe animations and Web Animations API won’t work as intended</li>
</ul>
<p>About that last bullet point...</p>
<p>As I discussed in an article about <a href="https://danielcwilson.com/blog/2017/07/animating-single-div-art/">animating Single Div art</a>, the Custom Properties Level 1 specification does not introduce mechanisms to specify a syntax or value type for a given custom property. Therefore, the following will either do nothing or <a href="https://www.w3.org/TR/css-variables/#syntax">flip states at the 50% mark</a> in the animation:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.using-custom-properties</span> <span class="token punctuation">{</span><br /> <span class="token comment">/* using set up in last example */</span><br /> <span class="token property">animation</span><span class="token punctuation">:</span> move-it 1000ms infinite alternate<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token atrule"><span class="token rule">@keyframes</span> move-it</span> <span class="token punctuation">{</span><br /> <span class="token selector">25%</span> <span class="token punctuation">{</span><br /> <span class="token property">--translate-y</span><span class="token punctuation">:</span> 20vmin<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token selector">50%</span> <span class="token punctuation">{</span><br /> <span class="token property">--scale</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token selector">100%</span> <span class="token punctuation">{</span><br /> <span class="token property">--scale</span><span class="token punctuation">:</span> .8<span class="token punctuation">;</span><br /> <span class="token property">--rotate</span><span class="token punctuation">:</span> 90deg<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<h4 id="houdini-+-custom-properties" tabindex="-1">Houdini + Custom Properties <a class="direct-link" href="https://danielcwilson.com/blog/2017/10/all-the-transform-ways/#houdini-+-custom-properties" aria-hidden="true">#</a></h4>
<p>Except that animation can in fact work... in the future! And you can sneak into the future if you have the Experimental Web Platform Features flag enabled in Chrome as it has some initial Houdini magic in it. If you are new to Houdini (and almost all of us are) it’s central idea is that developers can write some JavaScript to tell the browser how to render CSS it doesn’t know what to do with by default. I highly recommend enabling the aforementioned flag in Chrome (under <code>chrome://flags</code>) and visiting this <a href="http://lab.iamvdo.me/houdini/">Houdini playground</a> (and its references) to get an idea of how it works and what is possible.</p>
<p>One of the simpler things that Houdini provides is a way to tell the browser that a specific custom property follows a certain syntax. Now we can tell the browser via JavaScript to treat our <code>--translate-x</code> custom property as a <code>length</code> value and our <code>--rotate</code> as an angle. With that small amount of extra information, the browser now has what it needs to do the keyframe animation as we would want.</p>
<p data-height="265" data-theme-id="0" data-slug-hash="eeOXpd" data-default-tab="css,result" data-user="danwilson" data-embed-version="2" data-pen-title="Houdini: Independent Transforms in Keyframes" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/eeOXpd/">Houdini: Independent Transforms in Keyframes</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<h3 id="3-compositeadd-animations" tabindex="-1">#3 Composite/Add Animations <a class="direct-link" href="https://danielcwilson.com/blog/2017/10/all-the-transform-ways/#3-compositeadd-animations" aria-hidden="true">#</a></h3>
<p>Now that you have a taste for the future and are okay with living in dev browsers and/or enabled flags, I want to talk about an old favorite of mine: the Web Animations API. This approach is not like the others and has a smaller use case, but it is still a way to work with transform functions independently.</p>
<p>There are times you have multiple animations going on for the same element — maybe one is changing the opacity, while the other is moving it across the screen. They can have different durations, easings, etc. In the Web Animations API you can achieve this with the following:</p>
<pre class="language-js"><code class="language-js">element<span class="token punctuation">.</span><span class="token function">animate</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br /> <span class="token literal-property property">transform</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'translateX(0)'</span><span class="token punctuation">,</span> <span class="token string">'translateX(20px)'</span><span class="token punctuation">]</span><br /><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">1500</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />element<span class="token punctuation">.</span><span class="token function">animate</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br /> <span class="token literal-property property">opacity</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token number">1</span><span class="token punctuation">]</span><br /><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Let’s change that to be two animations with two different <code>transform</code> setups.</p>
<pre class="language-js"><code class="language-js">element<span class="token punctuation">.</span><span class="token function">animate</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br /> <span class="token literal-property property">transform</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'translateX(0)'</span><span class="token punctuation">,</span> <span class="token string">'translateX(20px)'</span><span class="token punctuation">]</span><br /><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />element<span class="token punctuation">.</span><span class="token function">animate</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br /> <span class="token literal-property property">transform</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'rotate(0)'</span><span class="token punctuation">,</span> <span class="token string">'rotate(90deg)'</span><span class="token punctuation">]</span><br /><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">1500</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Since those are created and running at the same time, only the rotation is applied because they are modifying the same property and the first animation’s requested changes are effectively ignored.</p>
<p>But!</p>
<p>The Web Animations specification introduces the <a href="https://w3c.github.io/web-animations/#effect-composition"><code>composite</code> operation</a> (and the related <code>iterationComposite</code>). The default <code>composite</code> is <code>replace</code> and has the behavior we have had for years now where an animated property’s value simply replaces any previously set value — either from a rule set or another animation.</p>
<p>The <code>add</code> value is where things change from the previous norms. Taking our example above with the two <code>transform</code> animations, we can modify the second to use the new <code>composite</code> value of <code>add</code>.</p>
<pre class="language-js"><code class="language-js">element<span class="token punctuation">.</span><span class="token function">animate</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br /> <span class="token literal-property property">transform</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'translateX(0)'</span><span class="token punctuation">,</span> <span class="token string">'translateX(20px)'</span><span class="token punctuation">]</span><br /><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br /> <span class="token literal-property property">duration</span><span class="token operator">:</span> <span class="token number">1000</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">fill</span><span class="token operator">:</span> <span class="token string">'both'</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />element<span class="token punctuation">.</span><span class="token function">animate</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br /> <span class="token literal-property property">transform</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'rotate(0)'</span><span class="token punctuation">,</span> <span class="token string">'rotate(90deg)'</span><span class="token punctuation">]</span><br /><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br /> <span class="token literal-property property">duration</span><span class="token operator">:</span> <span class="token number">1500</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">fill</span><span class="token operator">:</span> <span class="token string">'both'</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">composite</span><span class="token operator">:</span> <span class="token string">'add'</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Now both animations will be seen as the browser on the fly figures out the appropriate transformation at a given point in the animation’s timeline accounting for both transformations. In our examples, the easing is <code>'linear'</code> by default, so we can break out what the effective <code>transform</code> is at any given point. Such as:</p>
<ul>
<li>0ms: <code>translateX(0px) rotate(0deg)</code></li>
<li>500ms: <code>translate(10px) rotate(30deg)</code> (halfway through first animation, 1/3 through second)</li>
<li>1000ms: <code>translate(20px) rotate(60deg)</code> (end of first, 2/3 through second)</li>
<li>1500ms: <code>translate(20px) rotate(90deg)</code> (end of second)</li>
</ul>
<p>The Web Animations API is in Firefox, Chrome, and Opera already. However, this piece of functionality is currently only in Firefox Nightly. You can see it in action in that browser (Nightly is v58 as of this writing) in the following samples. If you view them in another browser you will see the typical <code>replace</code> behavior instead.</p>
<p data-height="262" data-theme-id="0" data-slug-hash="NaYOrr" data-default-tab="js,result" data-user="danwilson" data-embed-version="2" data-pen-title="Animation Composite Add (Firefox Nightly)" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/NaYOrr/">Animation Composite Add (Firefox Nightly)</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<p data-height="265" data-theme-id="0" data-slug-hash="vyqpby" data-default-tab="js,result" data-user="danwilson" data-embed-version="2" data-pen-title="Animation Composite Tests (WAAPI)" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/vyqpby/">Animation Composite Tests (WAAPI)</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<p>There is also an ongoing <a href="https://github.com/w3c/csswg-drafts/issues/1594">discussion in the CSS Working Group</a> about adding this functionality to CSS, even beyond the context of animations.</p>
<p><em>Pros</em></p>
<ul>
<li>Allowed in animations and transitions started by the Web Animations API</li>
<li>Any number of transformations are allowed</li>
<li>Order can be controlled, but depends on which animations have the <code>composite: 'add'</code> option</li>
</ul>
<p><em>Cons</em></p>
<ul>
<li>Still working on spec</li>
<li>Only in Firefox Nightly currently</li>
<li>Only defined in Web Animations API (at the moment)</li>
<li>Less relevant for the non-animated use cases for separating transformations</li>
</ul>
<h3 id="are-there-more" tabindex="-1">Are there more? <a class="direct-link" href="https://danielcwilson.com/blog/2017/10/all-the-transform-ways/#are-there-more" aria-hidden="true">#</a></h3>
<p>There surely are other ways to accomplish this (such as doing a lot of calculations in a <code>requestAnimationFrame</code> or specifying all the different combinations possible in CSS), but these three represent the solutions with the least overhead and have the future in mind. It bears repeating that not everything discussed works today and none of these are in every browser that is available.</p>
<p>It doesn’t really bear repeating, though; that’s just how the web works. There is nothing wrong with looking to the future, and seeing how emerging technology is solving the problems of today.</p>
Animating Single Div Art2017-07-13T00:00:00Zhttps://danielcwilson.com/blog/2017/07/animating-single-div-art/<p class="preamble">This article originally appeared on <a href="https://css-tricks.com/animating-single-div-art/">CSS Tricks</a> on May 31, 2017.</p>
<p>When you dig deep with your tools, it is amazing what you can create out of the most basic of HTML. I have been constantly impressed with “Single Div Art” by <a href="http://a.singlediv.com/">Lynn Fisher</a> and others where you take a single generic <code><div></code> to create a beautiful <a href="http://a.singlediv.com/#cactus2">cactus</a>, <a href="http://a.singlediv.com/#alamo">Alamo</a>, or panda.</p>
<p data-height="255" data-theme-id="1" data-slug-hash="RKRmxx" data-default-tab="css,result" data-user="lynnandtonic" data-embed-version="2" data-pen-title="#dailycssimages 01: Bear Cub " class="codepen">See the Pen <a href="https://codepen.io/lynnandtonic/pen/RKRmxx/">#dailycssimages 01: Bear Cub </a> by Lynn Fisher (<a href="https://codepen.io/lynnandtonic">@lynnandtonic</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<p>It can be hard to jump in and deconstruct how these are made, due to the fact they are using layers of background gradients, box shadows, text shadows, and more in the midst of just a single div and its <code>::before</code> and <code>::after</code> pseudo elements. Before we go any further… check out Lynn Fisher’s article on <a href="https://hacks.mozilla.org/2014/09/single-div-drawings-with-css/">why and how she started working with single div art</a>.</p>
<p>One thing that single <code>div</code> pieces rarely do is animate. If you can transform your <code>div</code> or one of its pseudo elements, that’s fair (as Lynn Fisher does with her fantastic <a href="http://a.singlediv.com/#bb8">BB-8</a> <code>[div](http://a.singlediv.com/#bb8)</code>). But you cannot directly change the <code>opacity</code> or <code>transform</code> of the individual “elements” you create inside your <code>div</code>, since they are not actual DOM elements.</p>
<p>I am a big believer of trying something a little different and interesting to learn tools you otherwise might never learn. Working with the constraints of a single <code>div</code> might not be great for production work, but it can be a great exercise (and challenge) to stretch your skills in a fun way. In that spirit, we’ll use this technique to explore how Custom Properties (CSS Variables) work and even provide us a path to animation inside our <code>div</code>. To illustrate along the way we will be breaking down the following example with multiple animation approaches:</p>
<p data-height="265" data-theme-id="0" data-slug-hash="BRdJVZ" data-default-tab="result" data-user="danwilson" data-embed-version="2" data-pen-title="Single Div Accordion (Animated with CSS Variables)" class="codepen">See the Pen <a href="http://codepen.io/danwilson/pen/BRdJVZ/">Single Div Accordion (Animated with CSS Variables)</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<p>This accordion (the instrument, not the UI construct) has three main parts, the keyboard side (our <code>div</code>), the bellows (the part that squeezes, which is the <code>div::before</code>), and the button side (<code>div::after</code>). Since the accordion naturally divides into these pieces, we can <code>transform</code> each piece inside CSS Keyframe animations to get our animation started. The bellows are going between different <code>scaleX</code> values and the two sides are using countering <code>translateX</code> values to move with the scaling bellows. Thus, the squeezebox is born.</p>
<p data-height="265" data-theme-id="1" data-slug-hash="XRZEBJ" data-default-tab="css,result" data-user="danwilson" data-embed-version="2" data-pen-title="Single Div Accordion Breakdown: Transforms" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/XRZEBJ/">Single Div Accordion Breakdown: Transforms</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<h3 id="organizing-the-lessdivgreater-with-css-custom-properties" tabindex="-1">Organizing the <code><div></code> with CSS Custom Properties <a class="direct-link" href="https://danielcwilson.com/blog/2017/07/animating-single-div-art/#organizing-the-lessdivgreater-with-css-custom-properties" aria-hidden="true">#</a></h3>
<p>Animating and thinking about the three big pieces is more straightforward than thinking about what appears inside. It can be helpful to group and name the individual bits inside the <code>div</code>, and Custom Properties provide us a native way to do this. Instead of levels of seemingly infinite linear gradient stops, you can define the <code>-white-key</code>s and <code>--black-key</code>s for a piano keyboard. Instead of a cross-section of multiple layered gradients you can have a <code>--tea-cup</code> with its individual <code>--tea-bag</code> and a related <code>--tea-bag-position</code> defined inside.</p>
<p>The left side of the accordion boils down to:</p>
<pre class="language-css"><code class="language-css"><span class="token property">background</span><span class="token punctuation">:</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--shine<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--shine<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--button-key1<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--button<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--button-key2<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--button<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--button-key3<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--button<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--black-keys<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--white-keys<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--keyboard-base<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Those variable values might be several lines long (even hundreds), but conceptually how the layers of the keyboard come into play are clearer thanks to the variables.</p>
<p data-height="265" data-theme-id="1" data-slug-hash="VbQXjj" data-default-tab="css,result" data-user="danwilson" data-embed-version="2" data-pen-title="Single Div Accordion Breakdown: Keyboard" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/VbQXjj/">Single Div Accordion Breakdown: Keyboard</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<p>While the same can be done with Sass or Less, Custom Properties allow us to modify these values in the future. We can now conceptually think about animating just our <code>--button-key2</code> or the accordion’s decorative <code>--shine</code>. There are a few ways to tackle this.</p>
<h3 id="animating-large-property-values-with-css-keyframes" tabindex="-1">Animating Large Property Values with CSS Keyframes <a class="direct-link" href="https://danielcwilson.com/blog/2017/07/animating-single-div-art/#animating-large-property-values-with-css-keyframes" aria-hidden="true">#</a></h3>
<p>The first way is to use CSS keyframe animations to change the property that contains the piece you want to move. If you want to change something inside your background (say, for example, we want to change the color of our “shine” lines from red to blue), you can set swap out values in the <code>background</code> property. Building on the previous code sample:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">div</span> <span class="token punctuation">{</span><br /> <span class="token comment">/* using background definition from earlier */</span><br /> <span class="token property">--shine</span><span class="token punctuation">:</span> <span class="token function">linear-gradient</span><span class="token punctuation">(</span>to right<span class="token punctuation">,</span> transparent 29.5%<span class="token punctuation">,</span> red 29.5%<span class="token punctuation">,</span> red 70.5%<span class="token punctuation">,</span> transparent 70.5%<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property">--shine-blue</span><span class="token punctuation">:</span> <span class="token function">linear-gradient</span><span class="token punctuation">(</span>to right<span class="token punctuation">,</span> transparent 29.5%<span class="token punctuation">,</span> blue 29.5%<span class="token punctuation">,</span> blue 70.5%<span class="token punctuation">,</span> transparent 70.5%<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property">animation</span><span class="token punctuation">:</span> modify-shine 2000ms infinite alternate ease-in-out<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token atrule"><span class="token rule">@keyframes</span> modify-shine</span> <span class="token punctuation">{</span><br /> <span class="token selector">100%</span> <span class="token punctuation">{</span><br /> <span class="token property">background</span><span class="token punctuation">:</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--shine-blue<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token comment">/*these two replace the original --shine*/</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--shine-blue<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token comment">/* the rest of the background remains unchanged */</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--button-key1<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--button<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--button-key2<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--button<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--button-key3<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--button<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--black-keys<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--white-keys<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--keyboard-base<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>This give us a lot, especially since <code>background</code> is animatable (as are <code>text-shadow</code> and <code>box-shadow</code>). In this example there would be a transition from red to blue.</p>
<p>If your property is long, this can be hard to maintain, though Custom Properties can give us a help by extracting out the parts that don’t change to minimize the repetition. We can take it further by abstracting out pieces that don’t need to animate into a new variable - resulting in levels of variables:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">div</span> <span class="token punctuation">{</span><br /> <span class="token property">--static-component</span><span class="token punctuation">:</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--button-key1<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--button<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--button-key2<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--button<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--button-key3<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--button<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--black-keys<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--white-keys<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--keyboard-base<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property">background</span><span class="token punctuation">:</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--shine<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--shine<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--static-component<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token atrule"><span class="token rule">@keyframes</span> modify-shine</span> <span class="token punctuation">{</span><br /> <span class="token selector">100%</span> <span class="token punctuation">{</span><br /> <span class="token property">background</span><span class="token punctuation">:</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--shine-blue<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--shine-blue<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--static-component<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>The three musical notes in the accordion are based on this approach by animating <code>text-shadow</code>.</p>
<p data-height="289" data-theme-id="1" data-slug-hash="PmELQe" data-default-tab="css,result" data-user="danwilson" data-embed-version="2" data-pen-title="Single Div Accordion Breakdown: Music Notes" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/PmELQe/">Single Div Accordion Breakdown: Music Notes</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<h3 id="animating-with-custom-properties-inside-css-keyframes" tabindex="-1">Animating with Custom Properties inside CSS Keyframes <a class="direct-link" href="https://danielcwilson.com/blog/2017/07/animating-single-div-art/#animating-with-custom-properties-inside-css-keyframes" aria-hidden="true">#</a></h3>
<p>A related way to change states is to directly change the custom property inside the <code>keyframes</code>.</p>
<pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@keyframes</span></span> <span class="token punctuation">{</span><br /> <span class="token selector">0%</span> <span class="token punctuation">{</span><br /> <span class="token property">--button1-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-primary<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token selector">100%</span> <span class="token punctuation">{</span><br /> <span class="token property">--button1-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-secondary<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>A custom property has no predefined behavior and is not a useful property until it is used with <code>var(…)</code>, so the spec states changing one’s value will cause it to <a href="https://www.w3.org/TR/css-variables/#syntax">flip its value at 50%</a>. This is the default behavior for all CSS properties that are not animatable and means it will not transition between the values.</p>
<p>You may have guessed since I already mentioned the spec that this is not available in all browsers. Currently, this is supported in Chrome and Opera only.</p>
<p>This will be a quick way to get jump states when it is supported across browsers. If you are viewing this in Chrome or Opera, the accordion uses this approach to animate the keys on the keyboard and the buttons on the right side. For a smaller example, here is a “Pixel Art” example using this approach where the eyes and eyebrows will move in Blink browsers. Other browsers will nicely fall back to a static image. This is in many ways will use the least amount of code, but will have the least amount of support.</p>
<p data-height="265" data-theme-id="1" data-slug-hash="EmmVYL" data-default-tab="css,result" data-user="danwilson" data-embed-version="2" data-pen-title="Pixel Art Animated with Custom Properties" class="codepen">See the Pen <a href="http://codepen.io/danwilson/pen/EmmVYL/">Pixel Art Animated with Custom Properties</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<h3 id="animating-custom-property-values-via-javascript" tabindex="-1">Animating Custom Property Values via JavaScript <a class="direct-link" href="https://danielcwilson.com/blog/2017/07/animating-single-div-art/#animating-custom-property-values-via-javascript" aria-hidden="true">#</a></h3>
<p>A third method is to use JavaScript to set new property values directly (or apply classes that have different property values). In its basic form this could be a call to <code>setInterval</code> to toggle an on/off state for a value (for our piano this could be a key pressed or not).</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> div <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">var</span> active <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br /><span class="token function">setInterval</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> active <span class="token operator">=</span> <span class="token operator">!</span>active<span class="token punctuation">;</span><br /> div<span class="token punctuation">.</span>style<span class="token punctuation">.</span><span class="token function">setProperty</span><span class="token punctuation">(</span><span class="token string">'--white-key-1'</span><span class="token punctuation">,</span><br /> <span class="token string">'var(--white-key-color-'</span> <span class="token operator">+</span> <span class="token punctuation">(</span>active <span class="token operator">?</span> <span class="token string">'active'</span> <span class="token operator">:</span> <span class="token string">'default'</span><span class="token punctuation">)</span> <span class="token operator">+</span><span class="token string">')'</span><span class="token punctuation">)</span><br /><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>With the corresponding CSS:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">div</span> <span class="token punctuation">{</span><br /> <span class="token property">--white-key-1</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--white-key-color-default<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property">--white-key-color-default</span><span class="token punctuation">:</span> #fff<span class="token punctuation">;</span><br /> <span class="token property">--white-key-color-active</span><span class="token punctuation">:</span> #ddd<span class="token punctuation">;</span><br /> <span class="token comment">/* And a linear gradient that follows the following pattern */</span><br /> <span class="token property">background</span><span class="token punctuation">:</span> <span class="token function">linear-gradient</span><span class="token punctuation">(</span>to right<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>-white-key-1<span class="token punctuation">)</span> 5%<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--white-key-2<span class="token punctuation">)</span> 5%<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--white-key-2<span class="token punctuation">)</span> 10%<span class="token punctuation">,</span> ...<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p data-height="265" data-theme-id="1" data-slug-hash="mmqpGy" data-default-tab="css,result" data-user="danwilson" data-embed-version="2" data-pen-title="Single Div Piano Keys" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/mmqpGy/">Single Div Piano Keys</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<p>We are using JavaScript to set the <code>white-key-1</code> to be either the value from the variable <code>white-key-color-default</code> or <code>white-key-color-active</code> depending on its state.</p>
<p>This method is useful when toggling something on and off (such as with a direct change in size, position, or color). This is how the buttons on the right side of the accordion are animated (as a fallback when the Keyframe approach is not supported).</p>
<p data-height="265" data-theme-id="1" data-slug-hash="KmZJZQ" data-default-tab="css,result" data-user="danwilson" data-embed-version="2" data-pen-title="Single Div Accordion Breakdown: Right" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/KmZJZQ/">Single Div Accordion Breakdown: Right</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<p>Each of the nine buttons has CSS uses the following default circle, where <code>--color1</code> is a light blue and <code>--button-dim</code> is 1.4vmin:</p>
<pre class="language-css"><code class="language-css"><span class="token property">--button</span><span class="token punctuation">:</span> <span class="token function">radial-gradient</span><span class="token punctuation">(</span>circle<span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--color1<span class="token punctuation">)</span> <span class="token function">var</span><span class="token punctuation">(</span>--button-dim<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> transparent <span class="token function">var</span><span class="token punctuation">(</span>--button-dim<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>If i want to change a specific button later to a “pressed” state I can set up a specific value in the CSS, for example the fourth button:</p>
<pre class="language-css"><code class="language-css"><span class="token property">--button4</span><span class="token punctuation">:</span> <span class="token function">radial-gradient</span><span class="token punctuation">(</span>circle<span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--button4-color<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--color1<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">var</span><span class="token punctuation">(</span>--button4-dim<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--button-dim<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> transparent <span class="token function">var</span><span class="token punctuation">(</span>--button4-dim<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--button-dim<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>This property is similar, but it replaces the <code>--button-dim</code> and <code>--color1</code> with values that are specific to this button combined with a default value inside the <code>var()</code>. This default value can be specified in our variables by using the form <code>var(--my-specific-variable, 13px)</code>. We can take it a little further and even use another variable value as our default, e.g. <code>var(--my-specific-variable, var(--my-default-variable))</code>. This second form is what our previous code example uses to create a specific definition for our fourth button while keeping its default value the same. If you have buttons you want to remain unchanged, they can use the default <code>--button</code> property in a different <code>background-position</code>.</p>
<p>In the accordion example, <code>--button4-color</code> or <code>--button4-dim</code> are never explicitly defined in the CSS. So when loaded they use the default values of <code>--color1</code> and <code>--button-dim</code>. The JS ultimately modifies the values and creates our on/off animation.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> enabled <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br /><span class="token function">setInterval</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> enabled <span class="token operator">=</span> <span class="token operator">!</span>enabled<span class="token punctuation">;</span><br /> div<span class="token punctuation">.</span>style<span class="token punctuation">.</span><span class="token function">setProperty</span><span class="token punctuation">(</span><span class="token string">'--button4-dim'</span><span class="token punctuation">,</span> enabled <span class="token operator">?</span> <span class="token string">'1.2vmin'</span> <span class="token operator">:</span> <span class="token string">'var(--button-dim)'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> div<span class="token punctuation">.</span>style<span class="token punctuation">.</span><span class="token function">setProperty</span><span class="token punctuation">(</span><span class="token string">'--button4-color'</span><span class="token punctuation">,</span> enabled <span class="token operator">?</span> <span class="token string">'var(--color1alt)'</span> <span class="token operator">:</span> <span class="token string">'var(--color1)'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>This will give us behavior similar to changing the Custom Properties directly in a keyframe where values jump from state to state with no transition. As we’ve already discussed, <code>background</code> and the <code>*-shadow</code> properties are animatable (and transitionable… not in a high performance <code>transform</code> or <code>opacity</code> kind of way… but in small uses that can be okay).</p>
<p>If we take our current JS on/off approach and combine it with a CSS <code>transition</code> on the <code>background</code>, we can get a transition instead of a jump state.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">div</span> <span class="token punctuation">{</span><br /> <span class="token property">transition</span><span class="token punctuation">:</span> background 2000ms ease-in-out<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<h3 id="combining-with-requestanimationframe" tabindex="-1">Combining with requestAnimationFrame <a class="direct-link" href="https://danielcwilson.com/blog/2017/07/animating-single-div-art/#combining-with-requestanimationframe" aria-hidden="true">#</a></h3>
<p>Depending on how your individual components are composed, the ability to transition the property may not be possible. If you want to move something, you might need to look to <code>requestAnimationFrame</code>.</p>
<p>One of my favorite Single Divs out there is a backpack by Tricia Katz:</p>
<p data-height="349" data-theme-id="1" data-slug-hash="LbWVPj" data-default-tab="result" data-user="techxastrish" data-embed-version="2" data-pen-title="Single Div Backpack" class="codepen">See the Pen <a href="http://codepen.io/techxastrish/pen/LbWVPj/">Single Div Backpack</a> by Trish Katz (<a href="http://codepen.io/techxastrish">@techxastrish</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<p>I would love for that zipper to move back and forth. With a single custom property to represent the zipper’s <code>x</code> position we can reach for <code>requestAnimationFrame</code> to change that value and move the zipper right and left.</p>
<p data-height="367" data-theme-id="1" data-slug-hash="oWWbwz" data-default-tab="js,result" data-user="danwilson" data-embed-version="2" data-preview="true" data-pen-title="Single Div Backpack with CSS Variables for Animation" class="codepen">See the Pen <a href="http://codepen.io/danwilson/pen/oWWbwz/">Single Div Backpack with CSS Variables for Animation</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<h3 id="conclusion" tabindex="-1">Conclusion <a class="direct-link" href="https://danielcwilson.com/blog/2017/07/animating-single-div-art/#conclusion" aria-hidden="true">#</a></h3>
<p>There are several approaches to animating inside a <code>div</code> that can stretch your skills. To get the broadest support we can’t rely on CSS alone right now, though we can still get pretty far. Custom Properties make modifying values more direct, even when we need to combine with JavaScript (and we can lean on our variable naming to be clear what we are changing).</p>
<p data-height="236" data-theme-id="1" data-slug-hash="MmOXxR" data-default-tab="css,result" data-user="danwilson" data-embed-version="2" data-pen-title="Single Div Animation Options" data-preview="true" class="codepen">See the Pen <a href="http://codepen.io/danwilson/pen/MmOXxR/">Single Div Animation Options</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<p>Whenever you want to learn a new thing in CSS or JavaScript… see if you can find a “Single Div”-esque way to learn it. When you need to conceptually break properties apart or animate complicated values, Custom Properties can bring something new to the table.</p>
Scrubbing via the Web Animations API2017-06-19T00:00:00Zhttps://danielcwilson.com/blog/2017/06/scrubbing/<p>A question appeared on a <a href="https://css-tricks.com/css-animations-vs-web-animations-api/#comment-1609249">great Web Animations API article</a> on CSS Tricks about whether or not the API would ever support scrubbing through an animation. As is often the case it does support that, but at a lower level (meaning you can't just say <code>animation.showControlsPlease()</code>).</p>
<p data-height="325" data-theme-id="0" data-slug-hash="JJEoxq" data-default-tab="js,result" data-user="danwilson" data-embed-version="2" data-pen-title="Scrub Multiple Animations in WAAPI" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/JJEoxq/">Scrub Multiple Animations in WAAPI</a> by Dan Wilson (<a href="https://codepen.io/danwilson">@danwilson</a>) on <a href="https://codepen.io/">CodePen</a>.</p>
<h3 id="the-power-of-currenttime" tabindex="-1">The Power of <code>currentTime</code> <a class="direct-link" href="https://danielcwilson.com/blog/2017/06/scrubbing/#the-power-of-currenttime" aria-hidden="true">#</a></h3>
<p>Creating a player control like the scrubber is possible thanks to the API's <code>currentTime</code> property which is a read/write value that shows (or sets) what millisecond the animation is at. An animation with only one iteration will have a <code>currentTime</code> with a max value of the <code>duration</code> plus any delays.</p>
<p>Creating a scrubber for a single animation then becomes an exercise in <code>currentTime</code> management. Things get more interesting as we want to scrub through multiple animations as a group, which is where we will focus (though what is covered here can be simplified to handle <a href="https://codepen.io/danwilson/pen/weJdvo">scrubbing one animation</a>).</p>
<p>Our example focuses on five separate elements with one animation each (a <code>transform</code> that moves each element to the right with a rotation) that all have the same duration. Each additionally has a <code>delay</code> to stagger the animations. Since <code>currentTime</code> includes delays, as the <code>delay</code> gets bigger, so does the max <code>currentTime</code> value.</p>
<p>We add one useful property to the animations to counter the <code>delay</code>: an <code>endDelay</code>. This does not currently have a CSS animation counterpart, but effectively does what <code>delay</code> does... just at the end. This is particularly important when thinking about <code>currentTime</code>. If I can set up all my animations to start playing at the same time <em>and</em> stop playing at the same (again, both delays will be used to caluclate the max <code>currentTime</code> value), then I can use a single control/scrubber to affect all the animations at once.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> divs <span class="token operator">=</span> Array<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span>document<span class="token punctuation">.</span><span class="token function">querySelectorAll</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">var</span> animations <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br /><span class="token keyword">const</span> <span class="token constant">DURATION</span> <span class="token operator">=</span> <span class="token number">8000</span><span class="token punctuation">;</span><br /><br />divs<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">div<span class="token punctuation">,</span> i</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">var</span> anim <span class="token operator">=</span> div<span class="token punctuation">.</span><span class="token function">animate</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br /> <span class="token literal-property property">transform</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'translateX(0) rotate(0deg)'</span><span class="token punctuation">,</span> <span class="token string">'translateX(80vw) rotate(2700deg)'</span><span class="token punctuation">]</span><br /> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br /> <span class="token literal-property property">duration</span><span class="token operator">:</span> <span class="token constant">DURATION</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">easing</span><span class="token operator">:</span> <span class="token string">'ease-in-out'</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">fill</span><span class="token operator">:</span> <span class="token string">'both'</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">delay</span><span class="token operator">:</span> <span class="token constant">DURATION</span> <span class="token operator">/</span> <span class="token number">4</span> <span class="token operator">*</span> i<span class="token punctuation">,</span><br /> <span class="token literal-property property">endDelay</span><span class="token operator">:</span> <span class="token constant">DURATION</span> <span class="token operator">-</span> <span class="token punctuation">(</span><span class="token constant">DURATION</span> <span class="token operator">/</span> <span class="token number">4</span> <span class="token operator">*</span> i<span class="token punctuation">)</span><br /> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /> animations<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>anim<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Now all the animations will kick off at effectively the same time (since I am calling <code>animate()</code> all together). The <code>currentTime</code> will start counting up for each, even though they don't all start moving at once since <code>currentTime</code> includes <code>delay</code> and <code>endDelay</code>. Each has a duration of 8000ms, and each also has a delay/endDelay combination that adds up to 8000ms. Therefore, the five animations all will have a <code>currrentTime</code> that maxes out at 16000ms.</p>
<h3 id="the-controller" tabindex="-1">The Controller <a class="direct-link" href="https://danielcwilson.com/blog/2017/06/scrubbing/#the-controller" aria-hidden="true">#</a></h3>
<p>I'm using a simple unstyled HTML range input in this example to act as the scrubber with a min value of <code>0</code> and a max value of <code>16000</code> to match our min/max <code>currentTime</code>.</p>
<p>We need three things now:</p>
<ul>
<li>An animation of the range slider thumb when the animation is playing to keep in sync with the <code>currentTime</code></li>
<li>An event listener for when a user is dragging the slider to pause and set the <code>currentTime</code></li>
<li>An event listener to play the animation again when the user is done dragging</li>
</ul>
<p>When the animation is playing we can use <code>requestAnimationFrame</code> to move the range slider according to the <code>currentTime</code> of the animations.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> isPlaying <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br /><span class="token keyword">var</span> scrub <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'scrub'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token function">adjustScrubber</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">function</span> <span class="token function">adjustScrubber</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">if</span> <span class="token punctuation">(</span>isPlaying<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> scrub<span class="token punctuation">.</span>value <span class="token operator">=</span> animations<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>currentTime<span class="token punctuation">;</span><br /> <span class="token function">requestAnimationFrame</span><span class="token punctuation">(</span>adjustScrubber<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>When the user is scrubbing through the full animation we can pause our individual animations and set their <code>currentTime</code>s based on the range value:</p>
<pre class="language-js"><code class="language-js">scrub<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'input'</span><span class="token punctuation">,</span> <span class="token parameter">e</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">var</span> time <span class="token operator">=</span> e<span class="token punctuation">.</span>currentTarget<span class="token punctuation">.</span>value<span class="token punctuation">;</span> <span class="token comment">//The range's value will be: 0 <= val <= 16000</span><br /> animations<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">animation</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> animation<span class="token punctuation">.</span>currentTime <span class="token operator">=</span> time<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token function">pauseAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">function</span> <span class="token function">pauseAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> isPlaying <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br /> animations<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">animation</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> animation<span class="token punctuation">.</span><span class="token function">pause</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>Finally we can play everything again when we stop dragging and release the mouse/touch:</p>
<pre class="language-js"><code class="language-js">scrub<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'change'</span><span class="token punctuation">,</span> <span class="token parameter">e</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> <span class="token keyword">if</span> <span class="token punctuation">(</span>animations<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>currentTime <span class="token operator">>=</span> e<span class="token punctuation">.</span>currentTarget<span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span><span class="token string">'max'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token function">finishAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token function">requestAnimationFrame</span><span class="token punctuation">(</span>adjustScrubber<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token function">playAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">function</span> <span class="token function">playAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> isPlaying <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br /> animations<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">animation</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> animation<span class="token punctuation">.</span><span class="token function">play</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token keyword">function</span> <span class="token function">finishAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> isPlaying <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br /> animations<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">animation</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br /> animation<span class="token punctuation">.</span><span class="token function">finish</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>This has an additional check for when we stop dragging at the max value (16000). In that case we actually don't want it to play again, but we do want it to "finish" the animations and get them to their full end states. To keep <code>requestAnimationFrame</code> from firing forever once finished, we add an additional <code>onfinish</code> callback to one of the animations that toggle the <code>isPlaying</code> flag to false.</p>
<pre class="language-js"><code class="language-js">animations<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function-variable function">onfinish</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> isPlaying <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span><br /> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'finished'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<h3 id="the-wrap-up" tabindex="-1">The Wrap Up <a class="direct-link" href="https://danielcwilson.com/blog/2017/06/scrubbing/#the-wrap-up" aria-hidden="true">#</a></h3>
<p>One limitation of the example to note: The way I've structured the event listeners (a combination of <code>input</code> and <code>change</code> events) means it will work with touch/mouse... but not the arrow keys on a keyboard. I will be investigating better approaches for that to make this more accessible.</p>
<p>This scrubbing process requires a certain setup where all the animations start at the same time and have the same length. Going beyond this is possible with the current tools, but it requires a bit more thought and customization. Similar processes could be used to adjust the timeline based on scroll or other inputs.</p>
<p>We will have more options as the Web Animations API expands. The second level of the spec is exploring grouping and sequencing of animations such that there are multiple animations going along a shared timeline. I love that we can already accomplish a lot though with the default individual timelines and <code>currentTime</code> property.</p>
Making Custom Properties (CSS Variables) More Dynamic2017-06-07T00:00:00Zhttps://danielcwilson.com/blog/2017/06/dynamic-css-variables/<p class="preamble">This article originally appeared on <a href="https://css-tricks.com/making-custom-properties-css-variables-dynamic/">CSS Tricks</a> on May 10, 2017.</p>
<p>CSS Custom Properties (CSS Variables) provide us ways to make code more concise, as well as introduce new ways to work with CSS that were not possible before. They can do what preprocessor variables can… but also a lot more. Whether you have been a fan of the declarative nature of CSS or prefer to handle most of your style logic in JavaScript, Custom Properties bring something to the table for everyone.</p>
<p>Most of the power comes from two unique abilities of Custom Properties:</p>
<ul>
<li>The cascade</li>
<li>The ability to modify values with JavaScript</li>
</ul>
<p>Even more power is exposed as you combine Custom Properties with other preexisting CSS concepts, like <code>calc()</code>.</p>
<h3 id="the-basics" tabindex="-1">The Basics <a class="direct-link" href="https://danielcwilson.com/blog/2017/06/dynamic-css-variables/#the-basics" aria-hidden="true">#</a></h3>
<p>You can use Custom Properties to do effectively what variables in preprocessors like Sass provide - set a global or scoped variable value, and then use it later in your code. But thanks to the cascade, you can give new property values inside a more specific rule.</p>
<p>This cascading can lead to several interesting approaches, as shown by Violet Peña with an <a href="https://vgpena.github.io/winning-with-css-variables/">overview of the key benefits of variables</a> and Chris with <a href="https://css-tricks.com/css-custom-properties-theming/">a roundup of site theming options</a>.</p>
<p>People have been discussing these benefits from the cascade for a few years now, but it often gets lost in the conversation despite being a key functionality that differentiates it from preprocessors. Amelia Bellamy-Royds discussed it in <a href="https://codepen.io/AmeliaBR/post/customizable-svg-icons-css-variables">the context of SVG and <code>use</code></a> in 2014, Philip Walton noted a lot of <a href="https://philipwalton.com/articles/why-im-excited-about-native-css-variables/">these general cascading benefits</a> in 2015, and last year Gregor Adams showed how they can be used in <a href="https://codepen.io/pixelass/post/layout-powered-by-css-variables">a minimal grid framework</a>. Taking advantage of the cascade is likely the easiest way to start working with Custom Properties with progressive enhancement in mind.</p>
<p>Okay. Now that we know Custom Properties can natively give us some functionality preprocessors have and some new uses thanks to the cascade - do they give us anything we simply never could do before?</p>
<p>You bet!</p>
<h3 id="individualizing-properties" tabindex="-1">Individualizing Properties <a class="direct-link" href="https://danielcwilson.com/blog/2017/06/dynamic-css-variables/#individualizing-properties" aria-hidden="true">#</a></h3>
<p>All of the properties that have multiple parts are able to be used differently now. Multiple <code>background</code>s can be separated, and multiple <code>transition-duration</code>s can be broken out individually. Instead of taking a rule like <code>transform: translateX(10vmin) rotate(90deg) scale(.8) translateY(5vmin)</code> you can set one rule with several custom properties and change the values independently thereafter.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.view</span> <span class="token punctuation">{</span><br /> <span class="token property">transform</span><span class="token punctuation">:</span><br /> <span class="token function">translateX</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--tx<span class="token punctuation">,</span> 0<span class="token punctuation">)</span><span class="token punctuation">)</span><br /> <span class="token function">rotate</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--deg<span class="token punctuation">,</span> 0<span class="token punctuation">)</span><span class="token punctuation">)</span><br /> <span class="token function">scale</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--scale<span class="token punctuation">,</span> 1<span class="token punctuation">)</span><span class="token punctuation">)</span><br /> <span class="token function">translateY</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--ty<span class="token punctuation">,</span> 0<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token selector">.view.activated</span> <span class="token punctuation">{</span><br /> <span class="token property">--tx</span><span class="token punctuation">:</span> 10vmin<span class="token punctuation">;</span><br /> <span class="token property">--deg</span><span class="token punctuation">:</span> 90deg<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token selector">.view.minimize</span> <span class="token punctuation">{</span><br /> <span class="token property">--scale</span><span class="token punctuation">:</span> .8<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token selector">.view.priority</span> <span class="token punctuation">{</span><br /> <span class="token property">--ty</span><span class="token punctuation">:</span> 10vmin<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>It takes a bit to initialize, but then that little bit of extra effort up front sets you up to modify each transform function independently based on the needs of the class/selector rule. Your markup can then include any or all of the classes defined on each <code>.view</code> element and the <code>transform</code> will update appropriately, as <a href="https://codepen.io/danwilson/WjpKmz">the demo based on this code sample</a> shows.</p>
<p>While independent transform properties are coming (and at that time <code>translate</code>, <code>scale</code>, and <code>rotate</code> will be first level citizens), they are currently only in Chrome behind a flag. With Custom Properties you can get this functionality today with more support (and the additional ability to define your own order of functions, since <code>rotate(90deg) translateX(10vmin)</code> is different than <code>translateX(10vmin) rotate(90deg)</code>, for example).</p>
<p>If you are okay with them sharing the same timing options, they can even animate smoothly when using <code>transition</code> when changing any of the variables. It's kind of magical.</p>
<p data-height="319" data-theme-id="1" data-slug-hash="oBrOGW" data-default-tab="result" data-user="danwilson" data-embed-version="2" data-pen-title="CSS Variables + Transform = Individual Properties (with Inputs)" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/oBrOGW/">CSS Variables + Transform = Individual Properties (with Inputs)</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<h3 id="going-from-no-units-to-all-the-units" tabindex="-1">Going from No Units to All the Units <a class="direct-link" href="https://danielcwilson.com/blog/2017/06/dynamic-css-variables/#going-from-no-units-to-all-the-units" aria-hidden="true">#</a></h3>
<p>You can build on these concepts when combining with <code>calc()</code>. Instead of always setting variables as above with units (<code>--card-width: 10vmin</code> or <code>--rotation-amount: 1turn</code>) you can drop the units and use them in more places with a relation to one another. Now the values in our Custom Properties can be more dynamic than they already have been.</p>
<p>While <code>calc()</code> has been around for a few years now, it has arguably been most useful when trying to get a result from adding values with different units. For example, you have a fluid <code>width</code> in percentage units that needs to be shortened by 50px (<code>width: calc(100% - 50px)</code> ). However, <code>calc()</code> is capable of more.</p>
<p>Other operations like multiplication are allowed inside <code>calc</code> to adjust a value. The following is valid and gives us a sense that the transforms and filters are related to one another since they all use the number 10.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.colorful</span> <span class="token punctuation">{</span><br /> <span class="token property">transform</span><span class="token punctuation">:</span><br /> <span class="token function">translateX</span><span class="token punctuation">(</span><span class="token function">calc</span><span class="token punctuation">(</span>10 * 1vw<span class="token punctuation">)</span><span class="token punctuation">)</span><br /> <span class="token function">translateY</span><span class="token punctuation">(</span><span class="token function">calc</span><span class="token punctuation">(</span>10 * 1vh<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property">filter</span><span class="token punctuation">:</span> <span class="token function">hue-rotate</span><span class="token punctuation">(</span><span class="token function">calc</span><span class="token punctuation">(</span>10 * 4.5deg<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>This likely isn’t as common a use case because it is a calculation you don’t need the browser to compute. <code>10 * 1vw</code> will always be <code>10vw</code> so the calc gives us nothing. It can be useful when using a preprocessor with loops, but that is a smaller use case and can typically be done without needing CSS <code>calc``()</code> .</p>
<p>But what if we replace that repeated <code>10</code> with a variable? You can base values from a single value in multiple places, even with different units as well as open it up to change values in the future. The following is valid thanks to unitless variables and <code>calc</code>:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.colorful</span> <span class="token punctuation">{</span><br /> <span class="token property">--translation</span><span class="token punctuation">:</span> 10<span class="token punctuation">;</span><br /> <span class="token property">transform</span><span class="token punctuation">:</span><br /> <span class="token function">translateX</span><span class="token punctuation">(</span><span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--translation<span class="token punctuation">)</span> * 1vw<span class="token punctuation">)</span><span class="token punctuation">)</span><br /> <span class="token function">translateY</span><span class="token punctuation">(</span><span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--translation<span class="token punctuation">)</span> * 1vh<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property">filter</span><span class="token punctuation">:</span> <span class="token function">hue-rotate</span><span class="token punctuation">(</span><span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--translation<span class="token punctuation">)</span> * 4.5deg<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /> <span class="token property">will-change</span><span class="token punctuation">:</span> transform<span class="token punctuation">,</span> filter<span class="token punctuation">;</span><br /> <span class="token property">transition</span><span class="token punctuation">:</span> transform 5000ms ease-in-out<span class="token punctuation">,</span> filter 5000ms linear<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token selector">.colorful.go</span> <span class="token punctuation">{</span><br /> <span class="token property">--translation</span><span class="token punctuation">:</span> 80<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p data-height="436" data-theme-id="1" data-slug-hash="KmmKqy" data-default-tab="result" data-user="danwilson" data-embed-version="2" data-pen-title="Single Custom Property, Multiple Calcs" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/KmmKqy/">Single Custom Property, Multiple Calcs</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<p>The single value can be taken (initially 10, or later changed to 80... or any other number) and applied separately to <code>vw</code> units or <code>vh</code> units for a translation. You can convert it to <code>deg</code> for a rotation or a <code>filter: hue-rotate()</code>.</p>
<p>You don’t have to drop the units on the variable, but as long as you have them in your <code>calc</code> you can, and it opens up the option to use it in more ways elsewhere. Animation choreography to offset durations and delays can be accomplished by modifying the base value in different rules. In this example we always want <code>ms</code> as our end unit, but the key result we want is for our <code>delay</code> to always be half the animation’s <code>duration</code> . We then can do this by modifying only our <code>--duration-base</code>.</p>
<p data-height="421" data-theme-id="1" data-slug-hash="OmjRPX" data-default-tab="result" data-user="danwilson" data-embed-version="2" data-pen-title="Delay based on Duration" data-preview="true" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/OmjRPX/">Delay based on Duration</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<p>Even cubic beziers are up for Custom Properties modification. In the following example, there are several stacked boxes. Each one has a slightly smaller scale, and each is given a cubic bezier multiplier. This multiplier will be applied individually to the four parts of a baseline cubic-bezier. This allows each box to have a cubic bezier that is different but in relation to one another. Try removing or adding boxes to see how they play with one another. Press anywhere to translate the boxes to that point.</p>
<p data-height="419" data-theme-id="1" data-slug-hash="bWRreo" data-default-tab="result" data-user="danwilson" data-embed-version="2" data-pen-title="Spiral Trail... Kinda" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/bWRreo/">Spiral Trail... Kinda</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<p>JavaScript is used to randomize the baseline on each press, as well as setting up each box’s multiplier. The key part of the CSS, however, is:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.x</span> <span class="token punctuation">{</span><br /> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateX</span><span class="token punctuation">(</span><span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--x<span class="token punctuation">)</span> * 1px<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token comment">/* baseline value, updated via JS on press */</span><br /> <span class="token property">transition-timing-function</span><span class="token punctuation">:</span><br /> <span class="token function">cubic-bezier</span><span class="token punctuation">(</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--cubic1-1<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--cubic1-2<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--cubic1-3<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--cubic1-4<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token selector">.advanced-calc .x</span> <span class="token punctuation">{</span><br /> <span class="token property">transition-timing-function</span><span class="token punctuation">:</span><br /> <span class="token function">cubic-bezier</span><span class="token punctuation">(</span><br /> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--cubic1-1<span class="token punctuation">)</span> * <span class="token function">var</span><span class="token punctuation">(</span>--cubic1-change<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--cubic1-2<span class="token punctuation">)</span> * <span class="token function">var</span><span class="token punctuation">(</span>--cubic1-change<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--cubic1-3<span class="token punctuation">)</span> * <span class="token function">var</span><span class="token punctuation">(</span>--cubic1-change<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--cubic1-4<span class="token punctuation">)</span> * <span class="token function">var</span><span class="token punctuation">(</span>--cubic1-change<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>If you are viewing this in certain browsers (or are wondering why this example has an <code>.advanced-calc</code> class) you might already suspect there is an issue with this approach. There is indeed an important caveat... <code>calc</code> magic does not always work as expected across the browsers. Ana Tudor has long discussed the <a href="https://codepen.io/thebabydino/pen/wfraH">differences in browser support for</a> <code>calc</code> , and I have an additional test for some other <a href="https://codepen.io/danwilson/pen/ZKbxRv">simplified <code>calc</code> use cases</a>.</p>
<p>The good news: All the browsers that support Custom Properties also largely work with <code>calc</code> when converting to units like <code>px</code>, <code>vmin</code>, <code>rem</code>, and other linear distance units inside properties such as <code>width</code> and <code>transform: translate()</code>.</p>
<p>The not-so-good news: Firefox and Edge often have problems with other unit types, such as <code>deg</code>, <code>ms</code> , and even <code>%</code> in some contexts. So the previous <code>filter: hue-rotate()</code> and <code>--rotation</code> properties would be ignored. They even have problems understanding <code>calc(1 * 1)</code> in certain cases so even remaining unitless (such as inside <code>rgb()</code>) can be a problem.</p>
<p>While all the browsers that support Custom Properties will allow variables inside our <code>cubic-bezier</code> , not all of them allow <code>calc</code> at any level. I feel these <code>calc</code> issues are the main limiting factors with Custom Properties today… and they’re not even a part of Custom Properties.</p>
<p>There are bugs tracked in the browsers for these issues, and you can work around them with progressive enhancement. The earlier demos only do the <code>cubic-bezier</code> modifications if it knows it can handle them, otherwise you get the baseline values. They will erroneously pass a CSS <code>@supports</code> check, so a JS Modernizr-style check is needed:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">isAdvancedCalcSupported</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span>style<span class="token punctuation">.</span>transitionTimingFunction <span class="token operator">=</span> <span class="token string">'cubic-bezier(calc(1 \* 1),1,1,1)'</span><span class="token punctuation">;</span><br /> <span class="token keyword">return</span> <span class="token function">getComputedStyle</span><span class="token punctuation">(</span>document<span class="token punctuation">.</span>body<span class="token punctuation">)</span><span class="token punctuation">.</span>transitionTimingFunction <span class="token operator">!=</span> <span class="token string">'ease'</span><span class="token punctuation">;</span><br /> <span class="token comment">//if the browser does not understand it, the computed value will be the default value (in this case "ease")</span><br /><span class="token punctuation">}</span></code></pre>
<h3 id="interacting-via-javascript" tabindex="-1">Interacting via JavaScript <a class="direct-link" href="https://danielcwilson.com/blog/2017/06/dynamic-css-variables/#interacting-via-javascript" aria-hidden="true">#</a></h3>
<p>Custom Properties are great for what they provide in CSS, but more power is unlocked when you communicate via JavaScript. As shown in the <code>cubic-bezier</code> demo, we can write a new property value in JavaScript:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> element <span class="token operator">=</span> document<span class="token punctuation">.</span>documentElement<span class="token punctuation">;</span><br />element<span class="token punctuation">.</span>style<span class="token punctuation">.</span><span class="token function">setProperty</span><span class="token punctuation">(</span><span class="token string">'--name'</span><span class="token punctuation">,</span> value<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>This will set a new value for a globally defined property (in CSS defined in the <code>:root</code> rule). Or you can go more direct and set a new value for a specific element (and thus give it the highest specificity for that element, and leave the variable unchanged for other elements that use it). This is useful when you are managing state and need to modify a style based on given values.</p>
<p>David Khourshid has discussed powerful ways to interact with Custom Properties via JS in <a href="http://slides.com/davidkhourshid/reactanim#/">the context of Observables</a> and they really fit together nicely. Whether you want to use Observables, React state changes, tried-and-true event listeners, or some other way to derive value changes, a wide door is now open to communicate between the two.</p>
<p>This communication is especially important for the CSS properties that take multiple values. We've long had the <code>style</code> object to modify styles from JavaScript, but that can get complicated as soon as we need to modify only one part of a long value. If we need to change one background out of ten that are defined in a <code>background</code> rule, we have to know which one we are modifying and then make sure we leave the other nine alone. This gets even more complicated for <code>transform</code> rules when you are trying to only modify a <code>rotate()</code> and keep the current <code>scale()</code> unchanged. With Custom Properties you can use JavaScript to modify each individually, simplifying the state management of the full <code>transform</code> property.</p>
<p data-height="506" data-theme-id="1" data-slug-hash="LWPavK" data-default-tab="result" data-user="danwilson" data-embed-version="2" data-pen-title="Dance of the Hexagons and Variables" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/LWPavK/">Dance of the Hexagons and Variables</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<p>The unitless approach works well here, too. Your <code>setProperty()</code> calls can pass raw numbers to CSS instead of having to append units, which can simplify your JavaScript in some cases.</p>
<h3 id="is-it-time-to-use-this" tabindex="-1">Is it Time to Use This? <a class="direct-link" href="https://danielcwilson.com/blog/2017/06/dynamic-css-variables/#is-it-time-to-use-this" aria-hidden="true">#</a></h3>
<p>As Custom Properties are now in the latest browsers from Mozilla, Google, Opera, Apple, and Microsoft - it's definitely a good time to explore and experiment. A lot of what is discussed here can be used now with sensible fallbacks in place. The <code>calc</code> updates needed in some of the browsers are further out, but there are still times when you can reasonably use them. For example, if you work on hybrid mobile apps that are limited to more recent iOS, Android, or Windows versions you will have more room to play.</p>
<p>Custom Properties present a big addition to CSS, and it can take some time to wrap your head around how it all works. Dip your toes in, and then dive in if it suits you.</p>
Individualizing CSS Properties with CSS Variables2017-04-07T00:00:00Zhttps://danielcwilson.com/blog/2017/04/individualized-properties/<p>In <a href="https://danielcwilson.com/blog/2017/02/individual-transforms">"A Trick: Individual CSS Transform Functions"</a>, I discussed how we could use CSS Variables (Custom Properties) to bring us close to independent transform properties. Each day I explore CSS Variables, however, I'm finding they can help us with any property that accepts multiple values at the same time.</p>
<p data-height="265" data-theme-id="0" data-slug-hash="WpBEBX" data-default-tab="js,result" data-user="danwilson" data-embed-version="2" data-pen-title="Pause Independent Animations with CSS Variables" data-preview="true" data-editable="true" class="codepen">See the Pen <a href="http://codepen.io/danwilson/pen/WpBEBX/">Pause Independent Animations with CSS Variables</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<p>This example shows a block of text that animates via <code>clip-path</code> to reveal itself over another block of text. I've added a second keyframe animation to do a <code>hue-rotate</code> <code>filter</code> to effectively cycle through colors for the background. The <code>animation</code> property therefore has two values: one for each animation. If I want to change anything later for only one animation - such as a <code>duration</code> or <code>play-state</code>, I would likely take one of two approaches (Let's talk about toggling the <code>animation-play-state</code> from <code>paused</code> to <code>running</code>):</p>
<ol>
<li>Set up multiple classes to represent all the different combinations of play state we can have (in our case four: <code>running,running</code>; <code>running,paused</code>; <code>paused,running</code>; <code>paused,paused</code>;), and use JavaScript to determine the correct one and toggle the class. (A <a href="https://codepen.io/shshaw/pen/gmJvPW/">fork of this example</a> on CodePen by <a href="https://codepen.io/shshaw/">Shaw</a> shows how you can take this approach and still make this with a small amount of code via the checkbox hack)</li>
<li>Or: use JavaScript to <code>getComputedStyle</code> on our animating element, tokenize the value based on the comma, set the desired value on the one we want to update, and then join back together for a final result string to be set on the element's <code>style.animationPlayState</code>.</li>
</ol>
<p>These approaches have drawbacks, since they both grow more complex as we add more animations. We need nine classes if we have three animations and more complicated JS to get the right class applied. For the second option, we need to add additional logic to our JS any time a new animation is added, and we need to be careful to not change order in our CSS.</p>
<p>Instead, our example shows how we can use CSS Variables to break them apart and think of them more individually. We set up our <code>animation</code> as we normally would but we also set a separate <code>animation-play-state</code> property value, with the default values of running:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">main</span> <span class="token punctuation">{</span><br /> <span class="token property">--shape-play-state</span><span class="token punctuation">:</span> running<span class="token punctuation">;</span><br /> <span class="token property">--hue-play-state</span><span class="token punctuation">:</span> running<span class="token punctuation">;</span><br /><br /> <span class="token property">animation</span><span class="token punctuation">:</span><br /> reveal-shape 3000ms 1000ms infinite alternate ease-in-out both<span class="token punctuation">,</span><br /> hue-adjust 6000ms 0ms infinite alternate ease-in-out<span class="token punctuation">;</span><br /> <span class="token property">animation-play-state</span><span class="token punctuation">:</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--shape-play-state<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token function">var</span><span class="token punctuation">(</span>--hue-play-state<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>Now we can add some form controls that allow us to pause an individual animation via a small amount of JS:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">var</span> main <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'main'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">//Get Form controls with an id that syncs with the CSS Variable names</span><br />document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'shape'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> updatePlayState<span class="token punctuation">)</span><span class="token punctuation">;</span><br />document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'hue'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> updatePlayState<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">function</span> <span class="token function">updatePlayState</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">var</span> variable <span class="token operator">=</span> <span class="token string">'--'</span> <span class="token operator">+</span> e<span class="token punctuation">.</span>currentTarget<span class="token punctuation">.</span>id <span class="token operator">+</span> <span class="token string">'-play-state'</span><span class="token punctuation">;</span><br /> main<span class="token punctuation">.</span>style<span class="token punctuation">.</span><span class="token function">setProperty</span><span class="token punctuation">(</span>variable<span class="token punctuation">,</span> e<span class="token punctuation">.</span>currentTarget<span class="token punctuation">.</span>checked <span class="token operator">?</span> <span class="token string">'paused'</span> <span class="token operator">:</span> <span class="token string">'running'</span><span class="token punctuation">)</span><br /><span class="token punctuation">}</span></code></pre>
<p>This allows us to break out of manipulating full property values when we only need to update a small segment. We could take this further and add controls to everything... for each animation's durations, direction, iteration count, etc. It's not just CSS Animations and Transforms that take multiple values/functions in their properties and benefit from this approach.</p>
<p>We can use CSS Variables to switch Hue, Saturation, and Lightness for <code>color: hsl()</code>:</p>
<p data-height="265" data-theme-id="0" data-slug-hash="BpbYmZ" data-default-tab="css,result" data-user="danwilson" data-embed-version="2" data-pen-title="HSL" class="codepen">See the Pen <a href="http://codepen.io/danwilson/pen/BpbYmZ/">HSL</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<p>We can combine it with "The Original CSS Variable" <code>currentColor</code> and theme a site:</p>
<p data-height="265" data-theme-id="0" data-slug-hash="bqxRgj" data-default-tab="css,result" data-user="danwilson" data-embed-version="2" data-pen-title="Site Theming with input[type=range]" class="codepen">See the Pen <a href="http://codepen.io/danwilson/pen/bqxRgj/">Site Theming with input[type=range]</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<p>We can even update the individual parts of a <code>cubic-bezier()</code> easing function on the fly:</p>
<p data-height="241" data-theme-id="0" data-slug-hash="wJOazR" data-default-tab="css,result" data-user="danwilson" data-embed-version="2" data-pen-title="Jump to Where You Press" data-preview="true" class="codepen">See the Pen <a href="http://codepen.io/danwilson/pen/wJOazR/">Jump to Where You Press</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<p>Multiple backgrounds, box shadows, and more are open to this simplification. I've focused on using JS to manipulate values individually, but that certainly is not necessary. With backgrounds, for example, you could have the following instead of repeating all the parts for each variation (<a href="http://codepen.io/danwilson/pen/xqoejJ">See the Demo</a>):</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.card</span> <span class="token punctuation">{</span><br /> <span class="token property">--front</span><span class="token punctuation">:</span> <span class="token function">radial-gradient</span><span class="token punctuation">(</span>circle<span class="token punctuation">,</span> teal 20%<span class="token punctuation">,</span> teal 40%<span class="token punctuation">,</span> transparent 40%<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property">--mid</span><span class="token punctuation">:</span> <span class="token function">linear-gradient</span><span class="token punctuation">(</span>135deg<span class="token punctuation">,</span> transparent 20%<span class="token punctuation">,</span> cyan 20%<span class="token punctuation">,</span> cyan 50%<span class="token punctuation">,</span> transparent 40%<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property">--back</span><span class="token punctuation">:</span> <span class="token function">linear-gradient</span><span class="token punctuation">(</span>45deg<span class="token punctuation">,</span> cyan 40%<span class="token punctuation">,</span> hotpink 40%<span class="token punctuation">,</span> hotpink 60%<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /> <span class="token property">background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--front<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--mid<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--back<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token selector">.card.highlight</span> <span class="token punctuation">{</span><br /> <span class="token property">--front</span><span class="token punctuation">:</span> <span class="token function">radial-gradient</span><span class="token punctuation">(</span>circle<span class="token punctuation">,</span> yellow 20%<span class="token punctuation">,</span> yellow 60%<span class="token punctuation">,</span> transparent 60%<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token selector">.card.subdued</span> <span class="token punctuation">{</span><br /> <span class="token property">--mid</span><span class="token punctuation">:</span> <span class="token function">linear-gradient</span><span class="token punctuation">(</span>transparent<span class="token punctuation">,</span> transparent<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>If you understand and like the CSS cascade, CSS Variables will likely fit into your workflow well.</p>
<p>The latest Chrome, Safari, and Firefox do well with these examples (and as a side bonus: Firefox is only one version away from supporting <code>clip-path</code> without a flag). Edge 15, which was just released, is the first version to have CSS Variables, so I'm just starting to play with them there and... <a href="http://codepen.io/danwilson/pen/ZeaVLz/">they largely work</a>. Impressive for an initial release in my book, and the more common use cases for Variables seem to be working very well. The transition/animation ones do not always match the other browsers. Hopefully we will see improvements in all the browsers as we continue to explore what CSS Variables can do.</p>
A Trick: Individual CSS Transform Functions2017-02-21T00:00:00Zhttps://danielcwilson.com/blog/2017/02/individual-transforms/<p>We get a lot of power through the single <code>transform</code> property in CSS - allowing us to rotate, translate, scale, and more all at once. But allowing all of those different transform functions into one property can trip us up.</p>
<p>It's common to want to apply different transforms to different states of our elements. Say we have a button that we always want to be translated <code>-150%</code> vertically. When a user hovers over the button we scale the button down a bit, and on press (the active state) we rotate it 180 degrees. This example shows how one might first think to write the CSS for "My Button" as just described, and then the "Expected" button shows a way to get it as intended.</p>
<p data-height="237" data-theme-id="0" data-slug-hash="EZBvVV" data-default-tab="css,result" data-user="danwilson" data-embed-version="2" data-pen-title="Basics with Transform Functions" class="codepen">See the Pen <a href="http://codepen.io/danwilson/pen/EZBvVV/">Basics with Transform Functions</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<p>With the initial styles on the button we are not just adding the scale on hover... we are overriding the original translate as well, so it scales <em>and</em> transitions back to <code>translateY(0)</code>.</p>
<p>Why is this? Linear Algebra. The way these transformations happen depend on each other and their order (such that <code>translate(-50%, -50%) scale(.4) rotate(50deg)</code> is different than <code>rotate(50deg) translate(-50%, -50%) scale(.4)</code>), and they boil down to matrix multiplication. But we usually don't need to know transforms at that level. Web developers just want to know how they can maintain these transform functions at an individual level.</p>
<p data-height="223" data-theme-id="0" data-slug-hash="apgwrO" data-default-tab="css,result" data-user="danwilson" data-embed-version="2" data-pen-title="Order of Transform Functions" class="codepen">See the Pen <a href="http://codepen.io/danwilson/pen/apgwrO/">Order of Transform Functions</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<p>Chrome has begun implementing individual properties, such that <code>translate</code>, <code>rotate</code>, and <code>scale</code> become first class properties as seen in this previous example (as of this writing requires Chrome Canary). But this has limitations of its own:</p>
<ol>
<li>The <code>x</code>, <code>y</code>, and <code>z</code> pieces of each are still tied to a single property currently.</li>
<li>The order will always be <code>translate scale rotate</code> when it is converted to matrices.</li>
<li>Early days - just in Chrome Canary.</li>
</ol>
<h3 id="so-what-can-we-do" tabindex="-1">So what can we do? <a class="direct-link" href="https://danielcwilson.com/blog/2017/02/individual-transforms/#so-what-can-we-do" aria-hidden="true">#</a></h3>
<p>Use CSS Variables.</p>
<p>Listening to <a href="https://codepen.io/davidkpiano/">David Khourshid</a> talk about CSS Variables quickly opened my eyes to a lot of opportunities for animating with them. It wasn't until I started putting variables everywhere that their power became even clearer. Without further ado... here is the trick to give us more flexibility (with the how/what/why after the example).</p>
<p data-height="228" data-theme-id="0" data-slug-hash="oBrOGW" data-default-tab="css,result" data-user="danwilson" data-embed-version="2" data-pen-title="CSS Variables + Transform = Individual Properties" class="codepen">See the Pen <a href="https://codepen.io/danwilson/pen/oBrOGW/">CSS Variables + Transform = Individual Properties</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<p>We set up a key initial <code>transform</code> for our element with all the variables we intend to change. By modifying the variable value on the different states we can get a CSS rule that looks closer to our original code but with much more flexibility as the complexity grows. In this example we are dealing with many more states than the original example's three by introducing JavaScript (but this is not required: Here is a <a href="http://codepen.io/danwilson/pen/ggVPVQ">CSS only version of our original button example</a>). Still, it effectively is one CSS property defined, and we change only one transform function at a time (whether that be in JS or CSS).</p>
<p>Without the CSS variables we would have to do some calculations on the current transition when changing one of the transform functions (which may not be trivial). Then we could know where the other two functions are currently to make sure the transition remained smooth. Every time a variable is changed, a new transition occurs in the same way as if you had rewritten the <code>transform</code> property from scratch, so you still can't have different transitions for each transform function.</p>
<h3 id="how-does-this-compare-to-the-upcoming-individual-properties-in-chrome-canary" tabindex="-1">How does this compare to the upcoming individual properties in Chrome Canary? <a class="direct-link" href="https://danielcwilson.com/blog/2017/02/individual-transforms/#how-does-this-compare-to-the-upcoming-individual-properties-in-chrome-canary" aria-hidden="true">#</a></h3>
<ol>
<li>We can do any combination of <code>x</code>, <code>y</code>, and <code>z</code> since we choose how to set up our initial <code>transform</code>.</li>
<li>Similarly, we can even do whatever order of the transform functions we want (though we lose the (likely) less common use case of changing the order around between states).</li>
<li>I've seen this work well in latest Chrome (56), Firefox (50), and Safari (10.1 on Mac, iOS 10.3) (version 10 supported variables but did not do a smooth transition). Additionally, the latest Windows 10 (Creators Update) releases April 11, 2017, and its new version of Edge supports CSS Variables, so we will soon see how this works there.</li>
</ol>
<p>Please <a href="https://twitter.com/dancwilson">reach out</a> if you have some creative uses for this technique.</p>
A Different CSS Motion Path2017-01-02T00:00:00Zhttps://danielcwilson.com/blog/2017/01/different-css-motion-path/<p>When I first heard about the Web Animations API a few years ago, the most exciting piece was the promise of support for motion path animations - so that we could move/translate elements along a defined path instead of the linear default.</p>
<p>SVG has had this for years in most browsers, but the ability to use this with any DOM element brought new possibilities. A lot <a href="https://danielcwilson.com/blog/2015/09/animations-part-5/">changed after the initial announcement</a>, and a lot <a href="https://codepen.io/danwilson/post/css-motion-paths-2016">more has changed again</a>, and there are a lot of exciting things to come from this spec. To see some examples of the current spec, see <a href="http://codepen.io/collection/DjzrGP/">my demos</a> and <a href="http://codepen.io/collection/AQWaem/">others' demos</a> in Chrome 55+ or Opera 42+.</p>
<p>For now, I want to discuss what I had originally hoped the CSS Motion Path module would be (using CSS + SVG animations to illustrate, since this doesn't really exist).</p>
<h3 id="how-i-imagined-css-motion-path" tabindex="-1">How I Imagined CSS Motion Path <a class="direct-link" href="https://danielcwilson.com/blog/2017/01/different-css-motion-path/#how-i-imagined-css-motion-path" aria-hidden="true">#</a></h3>
<p>Instead of defining a path for an element and then animating its offset value to create motion along the path, I feel my ideal CSS Motion Path would tie more into existing transitions/animations.</p>
<h4 id="take-a-normal-translate" tabindex="-1">Take a normal translate <a class="direct-link" href="https://danielcwilson.com/blog/2017/01/different-css-motion-path/#take-a-normal-translate" aria-hidden="true">#</a></h4>
<p>For example, take a basic translation animation with a 2000ms duration with linear easing and an infinite iteration count via <code>transform: translate(25rem, 7.5rem)</code>:</p>
<figure id="standard-translate">
<div class="cssmp-example">
<div></div>
</div>
</figure>
<h4 id="...-and-a-path-from-svg" tabindex="-1">... and a path from SVG <a class="direct-link" href="https://danielcwilson.com/blog/2017/01/different-css-motion-path/#...-and-a-path-from-svg" aria-hidden="true">#</a></h4>
<figure>
<svg viewBox="0 0 300 100">
<path d="M0,100 C200,0 200,200 300,0" stroke-width="2" fill="none" stroke="#333" stroke-dashoffset="0" stroke-dasharray="8" id="path"></path>
<path d="M0,100 L 300,0" stroke-width="2" fill="none" stroke="#333" stroke-dashoffset="0" stroke-dasharray="8" id="control-path"></path>
</svg>
<figcaption>Path defined by the points <code>"M0,100 C200,0 200,200 300,0"</code> from a viewBox <code>"0 0 300 100"</code></figcaption>
</figure>
<h4 id="add-a-property-to-specify-the-path" tabindex="-1">Add a property to specify the path <a class="direct-link" href="https://danielcwilson.com/blog/2017/01/different-css-motion-path/#add-a-property-to-specify-the-path" aria-hidden="true">#</a></h4>
<p>For example:</p>
<p><code>translate-path: path("M0,100 C200,0 200,200 300,0")</code></p>
<h4 id="let-the-browser-map-the-points" tabindex="-1">Let the browser map the points <a class="direct-link" href="https://danielcwilson.com/blog/2017/01/different-css-motion-path/#let-the-browser-map-the-points" aria-hidden="true">#</a></h4>
<p>This is where I would pass the hard stuff to the browser (and why I understand this is a complicated issue). Assuming this could be achieved well, I'd expect the path to be rotated and scaled such that its start and end points match the start and end points of the translation.</p>
<p>So with the following CSS:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.circle</span> <span class="token punctuation">{</span><br /><span class="token property">animation</span><span class="token punctuation">:</span> go-forth 2000ms 0ms infinite linear<span class="token punctuation">;</span><br /><span class="token property">translate-path</span><span class="token punctuation">:</span> <span class="token function">path</span><span class="token punctuation">(</span><span class="token string">"M0,100 C200,0 200,200 300,0"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token atrule"><span class="token rule">@keyframes</span> go-forth</span> <span class="token punctuation">{</span><br /><span class="token selector">100%</span> <span class="token punctuation">{</span> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translate</span><span class="token punctuation">(</span>25rem<span class="token punctuation">,</span> 7.5rem<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>We could have the following animation (second dot is the reference of the default translation):</p>
<figure id="standard-plus-path">
<svg viewBox="0 0 300 140">
<use xlink:href="#path"></use>
<circle cx="0" cy="0" r="10" fill="#459cbd">
<animateMotion dur="2000ms" repeatCount="indefinite">
<mpath xlink:href="#path"></mpath>
</animateMotion>
</circle>
<circle cx="0" cy="0" r="10" fill="#459cbd" class="cssmp-control">
<animateMotion dur="2000ms" repeatCount="indefinite">
<mpath xlink:href="#control-path"></mpath>
</animateMotion>
</circle>
</svg>
</figure>
<p>Then if we only change the start and end points of our translation to be further apart and from the top/right to the bottom/left (with no change to anything related to the path) such as by changing our <code>keyframes</code> to:</p>
<pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@keyframes</span> go-forth</span> <span class="token punctuation">{</span><br /><span class="token selector">100%</span> <span class="token punctuation">{</span> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translate</span><span class="token punctuation">(</span>-26rem<span class="token punctuation">,</span> 52rem<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p>We'd have:</p>
<figure id="bigger-plus-path">
<svg viewBox="0 0 300 300">
<use xlink:href="#path"></use>
<circle cx="0" cy="0" r="5" fill="#459cbd">
<animateMotion dur="2000ms" repeatCount="indefinite">
<mpath xlink:href="#path"></mpath>
</animateMotion>
</circle>
<circle cx="0" cy="0" r="5" fill="#459cbd" class="cssmp-control">
<animateMotion dur="2000ms" repeatCount="indefinite">
<mpath xlink:href="#control-path"></mpath>
</animateMotion>
</circle>
</svg>
</figure>
<p id="wrap-up-cssmp">There are several use cases for the current spec, and in many ways I'm glad it is how it is. There's still a part of me, though, that finds more value in what I've just described. I will certainly admit that might just be due to habit - being used to animating transforms for the last several years.</p>
When to Use the Web Animations API2016-08-04T00:00:00Zhttps://danielcwilson.com/blog/2016/08/why-waapi/<p>Firefox 48 is now available, and with it comes the third browser (after Chrome and Opera) to support an initial feature set of the Web Animations API. With it, Brian Birtles goes into detail <a href="https://hacks.mozilla.org/2016/08/animating-like-you-just-dont-care-with-element-animate/">why this API is a big deal</a>. A few people have recently asked me why I talk so much about the API but still use CSS animations a lot of the time... so with Firefox's official release, here are some thoughts on when using JS might make more sense than CSS.</p>
<p>But first, a spoiler... I still typically prefer CSS for animating. You state an animation once, and all matching selectors will pick up on it without you having to iterate through them all. There's a reason over time we've seen things move from JS to CSS, and for me it's hard to beat declaring some rules in CSS and calling it a day.</p>
<h3 id="so-why-go-with-the-api" tabindex="-1">So Why Go with the API? <a class="direct-link" href="https://danielcwilson.com/blog/2016/08/why-waapi/#so-why-go-with-the-api" aria-hidden="true">#</a></h3>
<h4 id="dynamicrandomnew-values" tabindex="-1">Dynamic/Random/New Values <a class="direct-link" href="https://danielcwilson.com/blog/2016/08/why-waapi/#dynamicrandomnew-values" aria-hidden="true">#</a></h4>
<p>One of the main reasons to reach for JavaScript is when values are not static. For a basic Transition, you can use JS to modify a value to a <code>transition</code> property dynamically in one line such as <code>element.style.transitionDelay = '123ms'</code> and that's fine enough. However, modifying keyframe values on the fly is much more involved, such as adding a new stylesheet to the document with your new keyframes fully defined.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> frames <span class="token operator">=</span> <span class="token function">getFramesArray</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//get your new frames, e.g. [{offset: .5, transform: 'scale(1)'}]</span><br />animation <span class="token operator">=</span> <span class="token string">'@keyframes updatedAnimation {'</span><span class="token punctuation">;</span><br />frames<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">frame</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> animation <span class="token operator">+=</span> <span class="token punctuation">(</span>frame<span class="token punctuation">.</span>offset \<span class="token operator">*</span> <span class="token number">100</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">'% {transform:'</span> <span class="token operator">+</span> frame<span class="token punctuation">.</span>transform <span class="token operator">+</span> <span class="token string">'}'</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />animation <span class="token operator">+=</span> <span class="token string">'}'</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">var</span> style <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">"style"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />style<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>document<span class="token punctuation">.</span><span class="token function">createTextNode</span><span class="token punctuation">(</span>animation<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />document<span class="token punctuation">.</span>head<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>style<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">var</span> ele <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'toAnimate'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />ele<span class="token punctuation">.</span>style<span class="token punctuation">.</span>animationName <span class="token operator">=</span> <span class="token string">'updatedAnimation'</span><span class="token punctuation">;</span></code></pre>
<p>Instead the API can handle this directly, and in one spot.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> frames <span class="token operator">=</span> <span class="token function">getFramesArray</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//get your new frames, e.g. [{offset: .5, transform: ''}];</span><br /><span class="token keyword">var</span> ele <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'toAnimate'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />ele<span class="token punctuation">.</span><span class="token function">animate</span><span class="token punctuation">(</span>frames<span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Making randomized <a href="http://codepen.io/danwilson/pen/vKzbgd">confetti</a>, <a href="http://codepen.io/danwilson/pen/zveqab">snow</a>, and <a href="http://codepen.io/danwilson/pen/oXxKPd">springy objects</a> often requires less tinkering when using the API.</p>
<p data-height="265" data-theme-id="0" data-slug-hash="vKzbgd" data-default-tab="js,result" data-user="danwilson" data-embed-version="2" data-preview="true" class="codepen">See the Pen <a href="http://codepen.io/danwilson/pen/vKzbgd/">Confetti</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<p>For the confetti demo I actually combined both WAAPI and CSS. I used the WAAPI to generate random scale and horizontal placement values (also duration and negative delays), while animating inner divs with a 3D rotation and a wavering back and forth via CSS. I could have taken it further and animated everything with random values, but having only the container based on random values (for the primary confetti action of falling to the ground) was enough for it to feel spontaneous.</p>
<p>And yes, I agree - the phrase "primary confetti action" is one of the least confetti-related phrases a person can say.</p>
<h4 id="a-plethora-of-class-toggles" tabindex="-1">A Plethora of Class Toggles <a class="direct-link" href="https://danielcwilson.com/blog/2016/08/why-waapi/#a-plethora-of-class-toggles" aria-hidden="true">#</a></h4>
<p>If you're already doing a lot of logic to add and remove classes to trigger your CSS transitions or animations, the API might be a good way to go as well. That way all of your logic is in one place instead of two. Especially, if you are also needing to listen to animation events like <code>animationend</code> or <code>transitionend</code>. That is usually a sign to me that the only reason I'm using CSS is to take advantage of hardware acceleration (which you will get from browsers that support the WAAPI already).</p>
<p data-height="265" data-theme-id="0" data-slug-hash="755de1ba31b1629e4f662db0818185ac" data-default-tab="css,result" data-user="danwilson" data-embed-version="2" data-editable="true" class="codepen">See the Pen <a href="http://codepen.io/danwilson/pen/755de1ba31b1629e4f662db0818185ac/">755de1ba31b1629e4f662db0818185ac</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<h4 id="playback-control" tabindex="-1">Playback Control <a class="direct-link" href="https://danielcwilson.com/blog/2016/08/why-waapi/#playback-control" aria-hidden="true">#</a></h4>
<p>When you want to change the rate or be able to jump to different frames, the API will be the easiest way to do that now. It's all technically achievable with CSS now, but you have to take a fair amount of extra care to get timings right.</p>
<h4 id="chaining-multiple-animations" tabindex="-1">Chaining Multiple Animations <a class="direct-link" href="https://danielcwilson.com/blog/2016/08/why-waapi/#chaining-multiple-animations" aria-hidden="true">#</a></h4>
<p>Another reason is if you have complex animations that depend on other animations for when to start. The next level of the spec is introducing formal grouping and sequencing for multiple animations, but even now using the callbacks, <code>delay</code>, and <code>endDelay</code>s in the WAAPI can be a lot easier than managing your sequence of animations via <code>delay</code>s alone in CSS.</p>
<p>An excellent CSS-Tricks article <a href="https://css-tricks.com/comparison-animation-technologies/#article-header-id-1">comparing various animation methods</a> (by <a href="http://sarahdrasnerdesign.com/">Sarah Drasner</a>) covers the cons for CSS in detail.</p>
<h3 id="what-about-some-specifics" tabindex="-1">What about Some Specifics <a class="direct-link" href="https://danielcwilson.com/blog/2016/08/why-waapi/#what-about-some-specifics" aria-hidden="true">#</a></h3>
<p data-height="298" data-theme-id="0" data-slug-hash="wWZWKW" data-default-tab="result" data-user="danwilson" data-embed-version="2" data-preview="true" data-editable="true" class="codepen">See the Pen <a href="http://codepen.io/danwilson/pen/wWZWKW/">Falling Letters</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<p>I've used the Web Animations in a couple client projects because they were basic enough, but still benefited from the playback rate and timeline control.</p>
<p>You can also use features like canceling, <code>playbackRate</code> variance, dynamic elements/values, <code>onfinish</code> handlers, and more to create a game. The CodePen version of a game I recently created is shown here, with the full version now at <a href="https://lettersandsuch.herokuapp.com/">Letters and Such</a>. Effectively, letters (or other characters) fall, and you have to type the appropraite key before they reach the ground. Playback Rate is increased over time, letters and locations are randomized, and if the correct key is typed the animation is canceled (and you get a point, to boot). If the key is not pressed in time, however, the <code>onfinish</code> handler will be called and a "miss" is counted. The code in the CodePen is commented as far as the logic is concerned, so take a look for more detail.</p>
<p>There is nothing that would prevent you from making this with CSS animations. It made sense for me to keep the animations primarily in JS, especially since the animations drive a lot of the actual game logic.</p>
<h3 id="but-what-about-the-future" tabindex="-1">But What about the Future? <a class="direct-link" href="https://danielcwilson.com/blog/2016/08/why-waapi/#but-what-about-the-future" aria-hidden="true">#</a></h3>
<p>The Web Animations spec that underlies the Web Animations API is all about uniting JS and CSS methods. Firefox Nightly builds actually allow you to get all Animations on the document via JS, whether generated with the WAAPI, CSS Animations, or CSS Transitions. Right now some of the properties on CSS ones are read only (no changing of duration, for example), but already you can read/write the currentTime, pause these animations, or change playbackRate. There will be even less to differentiate the methods beyond personal preference as the spec matures.</p>
A Mouse, Some Touches, and All Sorts of Pointers2016-06-14T00:00:00Zhttps://danielcwilson.com/blog/2016/06/pointer-events/<p>If you've ever tried to support both touch and mouse events on the web you know there is a lot to consider, and you can get tripped up - especially when you accept that it is not an either/or situation. Pointer Events try to unify different input pointing devices so you don't have to think as differently for touch and mouse (or a stylus... or anything new that comes like an airtap), while also giving you access to the details that might be unique to each type.</p>
<p>Pointer Events have been around since 2012 and the introduction of Windows 8 with IE 10. Having used them when I made Windows apps for the launch of the Windows Store, I've been excited about their potential. They abstract enough of the similarities between different pointer types while still providing pressure on a device that allows it.</p>
<p>With their introduction recently in Chrome 52 behind a flag, they now are on track to be in three stable evergreen browsers (with support already in Edge and Firefox (behind a flag since last August)). We'll take a look at how to use them, how to enable the flags, and how to provide a fallback to mouse + touch in other browsers.</p>
<h3 id="give-me-the-basics-please" tabindex="-1">Give Me the Basics, Please <a class="direct-link" href="https://danielcwilson.com/blog/2016/06/pointer-events/#give-me-the-basics-please" aria-hidden="true">#</a></h3>
<p>Pointer Events provide a single event for mouse + touch + stylus + other future pointing devices. They have common mappings to Mouse Events, such as if you currently listen to <code>mousedown</code> you would instead listen to <code>pointerdown</code>.</p>
<p data-height="265" data-theme-id="0" data-slug-hash="rLabXy" data-default-tab="js,result" data-user="danwilson" data-embed-version="2" class="codepen">See the Pen <a href="http://codepen.io/danwilson/pen/rLabXy/">Pointer Event Logging</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<p>These events can be triggered: <code>pointerdown</code>, <code>pointermove</code>, <code>pointerup</code>, <code>pointerenter</code>, <code>pointerleave</code>, <code>pointerout</code>, <code>pointerover</code>, <code>pointercancel</code></p>
<p>In addition to the normal event properties (such as <code>pageX</code>) when an event fires you also are given the following:</p>
<ul>
<li><code>pointerId</code>: a unique identifier (Integer) so that you can keep track of the touch with which you are dealing</li>
<li><code>pointerType</code>: a string such as "mouse" or "touch"</li>
<li><code>pressure</code>: a number between 0 and 1 for the pressure if the input and device support it (0 represents a hover, and 0.5 will be the default for an input + device that does not support pressure but is pressing)</li>
<li><code>tiltX</code>: number in degress (from -90 to 90), <a href="https://www.w3.org/TR/pointerevents/#widl-PointerEvent-tiltX">visually described in the spec</a></li>
<li><code>tiltY</code>: similar to <code>tiltX</code>, also <a href="https://www.w3.org/TR/pointerevents/#widl-PointerEvent-tiltY">visually described in the spec</a></li>
<li><code>width</code> and <code>height</code>: dimensions (in CSS pixels) of the pointer. This will likely 1x1 for a mouse and something bigger for a touch, but is left to the browser to determine how to report it</li>
<li><code>button</code> and <code>buttons</code>: shows which button is changed and all buttons pressed, respectively.</li>
</ul>
<p><code>pointerId</code> and <code>pointerType</code> are the two properties that will appear regardless of the capabilities of the pointer.</p>
<h3 id="how-do-i-use-this-today" tabindex="-1">How Do I Use This Today? <a class="direct-link" href="https://danielcwilson.com/blog/2016/06/pointer-events/#how-do-i-use-this-today" aria-hidden="true">#</a></h3>
<p>There are three pieces you will want to remember when using Pointer Events:</p>
<ol>
<li>To check support, see if <code>window.PointerEvent</code> is present.</li>
<li>Listen to events as you would with other devices/input, such as <code>Element.addEventListener('pointerdown', function(e) {})</code></li>
<li>Set the <code>touch-action</code> CSS property to <code>none</code> (or other value than <code>auto</code>) on the element(s) that you want to receive Pointer Events.</li>
</ol>
<p>It's the third point that needs the most explanation. If you do not set this in CSS, your pointer events will fire fine for mouse, but might do nothing on touch (as determined by each browser). This is because the browser likely already has a lot of touch gestures that perform actions at the browser level, such as scrolling and zooming the viewport. By setting <code>touch-action: none</code> you are telling the browser to not perform those browser-level actions on the element and instead trigger Pointer Events. There are <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/touch-action">other values</a> that will allow you to continue some browser behaviors and then fire a subset of events.</p>
<p data-height="265" data-theme-id="0" data-slug-hash="MeYdrv" data-default-tab="css,result" data-user="danwilson" data-embed-version="2" class="codepen">See the Pen <a href="http://codepen.io/danwilson/pen/MeYdrv/">CSS Touch Action</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<p>For example, you could still want normal scrolling/panning on a given element, but still want to know when a <code>pointerdown</code> occurs via a JS event. In that case you could set <code>touch-action: pan</code>. You will no longer receive <code>pointermove</code> events for every finger movement. You could even limit this to a direction such as <code>touch-action: pan-y</code>, which will fire <code>pointermove</code> events for horizontal moves, but perform the default browser behavior for vertical movements (with no JS events sent).</p>
<p>Edge will not fire any Pointer Events if <code>touch-action</code> is <code>auto</code>, while Chrome and Firefox both currently treat <code>auto</code> similar to <code>pan</code>. So it is best to know and specify what you want for consistency between browsers.</p>
<p><a id="how-to-enable"></a></p>
<p>As of today, you can explore their uses in the following browsers</p>
<ul>
<li>Edge (and IE 11 (and IE10 with a prefix)): Supported</li>
<li>Firefox (41+): Enable the <code>dom.w3c_pointer_events.enabled</code> and <code>layout.css.touch_action.enabled</code> flags in <code>about:config</code></li>
<li>Chrome (52+): Enable the <code>Pointer Events</code> flag at <code>chrome://flags/#enable-pointer-events</code></li>
</ul>
<p>The fullest representation is Edge. In my testing Chrome and Firefox work well with a mouse or single touch point already, but have issues to resolve with multitouch.</p>
<h3 id="what-about-fallbacks" tabindex="-1">What about Fallbacks? <a class="direct-link" href="https://danielcwilson.com/blog/2016/06/pointer-events/#what-about-fallbacks" aria-hidden="true">#</a></h3>
<p>Almost everything in Pointer Events has a fallback either through Mouse Events or Touch Events. For example, Touch Events have an <code>identifier</code> that acts like <code>pointerId</code> and <code>force</code> which is similar to <code>pressure</code>.</p>
<p>I've not seen an equivalent for <code>tilt*</code>, so pen support will lack angles without Pointer Events. Though, it’s important to note <code>tilt</code> is only reported on a subset of pens (even the Surface Pro 4 pen does not support it in Edge).</p>
<p>We can use our support check to provide fallbacks</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">if</span> <span class="token punctuation">(</span>window<span class="token punctuation">.</span>PointerEvent<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /><span class="token comment">//register event listeners for Pointer Events</span><br /><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br /><span class="token comment">//register for mouse and touch</span><br /><span class="token punctuation">}</span></code></pre>
<p>Here is a full demo with multitouch and fallbacks. Press and the circles will surround your pointer. Release and they will fade away. If your pointer and device support it, more pressure/force will make the circles grow larger. 3D transforms occur when tilt values are detected.</p>
<p data-height="265" data-theme-id="0" data-slug-hash="LZpVpe" data-default-tab="js,result" data-user="danwilson" data-embed-version="2" data-preview="true" class="codepen">See the Pen <a href="http://codepen.io/danwilson/pen/LZpVpe/">Press & Hold</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<p>The caveats for this demo are the flagged releases of Chrome and Firefox. The Pointer events work well for mouse, pen, and a single touch point. When multiple touch points occur in Chrome and Firefox currently (flagged versions 52 and 48, respectively), it cannot keep up. Both browsers have work left before they become unflagged, and you can follow the status/bugs for both <a href="https://www.chromestatus.com/feature/4504699138998272">Chrome</a> and <a href="https://platform-status.mozilla.org/#pointer-events">Firefox</a> for updates.</p>
Promises in Web Animations2016-03-18T00:00:00Zhttps://danielcwilson.com/blog/2016/03/animations-and-promises/<p>When I first started learning about the Web Animations API there was one way to handle a "finish" event - the <code>onfinish</code> callback. It lets you assign it a function and that function is called when the animation is finished.</p>
<p>There is a newer way to handle this scenario, though... via the <code>finished</code> Promise. This either excites you (if you know what a Promise is), confuses you (if you know what a Promise is), or makes you ask what a Promise is. So...</p>
<h3 id="what-is-a-promise" tabindex="-1">What is a Promise? <a class="direct-link" href="https://danielcwilson.com/blog/2016/03/animations-and-promises/#what-is-a-promise" aria-hidden="true">#</a></h3>
<p>Promises have gone through several specs and implementations. A standardized version has found its way into <a href="http://caniuse.com/#feat=promises">most browsers</a> with Edge, Firefox, Safari, Chrome, and Opera's latest all supporting Promises. They are a feature in JavaScript similar to a callback in that they look for some code to finish running and then run some other code. With callbacks we often think of success and error handlers... with Promises we think of resolving and rejecting, such as:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">//set up 1 second animation to fade box out</span><br /><span class="token keyword">var</span> box <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'box'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">var</span> animation <span class="token operator">=</span> box<span class="token punctuation">.</span><span class="token function">animate</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">{</span> <span class="token literal-property property">opacity</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">opacity</span><span class="token operator">:</span> <span class="token number">0</span> <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">function</span> <span class="token function">finishedHandler</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'animation finished: '</span> <span class="token operator">+</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token keyword">function</span> <span class="token function">canceledHandler</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'animation canceled: '</span> <span class="token operator">+</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token comment">//the Promise version, log the timestamp when the Animation finishes</span><br />animation<span class="token punctuation">.</span>finished<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>finishedHandler<span class="token punctuation">,</span> canceledHandler<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token comment">//the effective successful equivalent with the onfinish callback</span><br />animation<span class="token punctuation">.</span>onfinish <span class="token operator">=</span> finishedHandler<span class="token punctuation">;</span></code></pre>
<p>This code starts an animation (by calling <code>animate()</code> on an element), and any other code will continue to execute while we wait for the animation to enter the "finished" state. Animations will expose a <code>finished</code> Promise that will "resolve" when the animation finishes. You can think of the Promise as a future object. When it resolves (in this case, a successful finish of the animation), the first function passed into the <code>then</code> will run. If the animation is rejected (the animation is canceled), it will run the second function passed to <code>then</code>, if specified.</p>
<p>For rejection, the current spec defines it this way, but there are <a href="https://github.com/w3c/web-animations/issues/141">discussions to change</a> away from this. We will focus on how to work with an animation that resolves for now...</p>
<h3 id="one-time-fits-all" tabindex="-1">One time fits all <a class="direct-link" href="https://danielcwilson.com/blog/2016/03/animations-and-promises/#one-time-fits-all" aria-hidden="true">#</a></h3>
<p>Promises by definition will either resolve or be rejected, and this resolution will only happen once. As soon as a Promise is resolved or rejected, it will not resolve nor reject again. Since animations can be played multiple times, this seems to be at odds with the Web animations API as subsequent finishes would not resolve again.</p>
<p>To solve this, the spec dictates a new Promise will replace the existing <code>finished</code> Promise when the play state changes to "running". This allows you to latch on to the Promise resolution state again, but you will have to add your handlers via <code>then</code> again.</p>
<pre class="language-js"><code class="language-js"><span class="token comment">//extending the previous example, play the animation second time</span><br />animation<span class="token punctuation">.</span><span class="token function">play</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token comment">//set 'then' to what spec states will be a newly created Promise</span><br />animation<span class="token punctuation">.</span>finished<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>finishedHandler<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br /><span class="token comment">//the onfinish from before remains</span></code></pre>
<p><em>Note: As of March 18, 2016 the polyfill has an <a href="https://github.com/web-animations/web-animations-js/issues/62">issue with resolving subsequent finished Promises</a> at the correct time.</em></p>
<h3 id="then-why-bother" tabindex="-1">Then Why Bother? <a class="direct-link" href="https://danielcwilson.com/blog/2016/03/animations-and-promises/#then-why-bother" aria-hidden="true">#</a></h3>
<p>Imagine a case where you want to trigger new animations when a given animation finishes. The following example shows two boxes, one using <code>onfinish</code> to start new animations and the second using the <code>finished</code> Promise.</p>
<p data-height="200" data-theme-id="0" data-slug-hash="wGgXbB" data-default-tab="result" data-user="danwilson" class="codepen">See the Pen <a href="http://codepen.io/danwilson/pen/wGgXbB/">Callbacks vs. Promises with Web Animations API</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<p>Callbacks will nest, and Promises can chain by returning a Promise. For this example it reads differently, and one might be more readable than the other to you. In fuller development the chaining can provide more power with how you manage your animation states and values. We will look into that in a future post.</p>
<p>There is a lot more to talk about with Promises... for much fuller discussions on Promises check out the <a href="https://ponyfoo.com/articles/es6-promises-in-depth">Ponyfoo</a> article on the topic and the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">MDN</a> article, especially their <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise#See_also">suggested reading</a>.</p>
<p class="postamble">Thanks to <a href="https://twitter.com/rachelnabors">Rachel</a> for triggering this discussion and <a href="https://twitter.com/simevidas">Šime</a> for pointing me to when an animation is rejected in the spec (and <a href="https://twitter.com/jaffathecake/status/711852704654471169">Jake</a> for mentioning the discussion about changing that). Thanks also to <a href="https://twitter.com/Nexii">Martin</a> for recommending additional Promise articles.</p>
Of Layouts with Columns2015-12-04T00:00:00Zhttps://danielcwilson.com/blog/2015/12/columns/<p class="preamble">I've been wanting to try this alternate large-screen layout out for a while, but there were quirks (more on those later) I hadn't resolved so I waited. Now that I (potentially) have resolved the issues I'm just going to flip the switch and see how these columns work out!</p>
<p>Mobile is always where I first read something, but I know that especially in the tech industry we still read on large monitors while working. It's weird that we have these large monitors but we still set <code>max-width</code>s on our content and force the user down a page. So... I'm trying out columns on my articles when you have a large and wide screen. Full width and horizontal scrolling - why not?</p>
<p>Columns, grid layouts, and other new methods for laying out pages have been emerging the last few years. I'll quickly admit I have not done user research or anything to validate what I'm trying here... it's simply my current exploration as to what we can try. Hopefully it works well for you, and if it doesn't I'd love to hear thoughts on why.</p>
<h3 id="so-how-does-it-work" tabindex="-1">So How Does it Work? <a class="direct-link" href="https://danielcwilson.com/blog/2015/12/columns/#so-how-does-it-work" aria-hidden="true">#</a></h3>
<p>Initially I'm rolling this out to what I (somewhat arbitrarily) deem a large enough viewport (1600x900), via the following media query:</p>
<pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@media</span> screen <span class="token keyword">and</span> <span class="token punctuation">(</span><span class="token property">min-width</span><span class="token punctuation">:</span> 100em<span class="token punctuation">)</span> <span class="token keyword">and</span> <span class="token punctuation">(</span><span class="token property">min-height</span><span class="token punctuation">:</span> 56.25em<span class="token punctuation">)</span></span> <span class="token punctuation">{</span><br /> <span class="token comment">/* ... */</span><br /><span class="token punctuation">}</span></code></pre>
<p>I also look to see support in browsers. The following should support all browsers that support <code>CSS.supports</code> and <code>column</code> (as well as IE 10 and 11 that have unprefixed <code>column</code> support but lack <code>CSS.supports</code>):</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>window<span class="token punctuation">.</span><span class="token constant">CSS</span> <span class="token operator">&&</span> window<span class="token punctuation">.</span><span class="token constant">CSS</span><span class="token punctuation">.</span>supports <span class="token operator">&&</span> <span class="token punctuation">(</span><span class="token constant">CSS</span><span class="token punctuation">.</span><span class="token function">supports</span><span class="token punctuation">(</span><span class="token string">'column-width'</span><span class="token punctuation">,</span> <span class="token string">'1px'</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token constant">CSS</span><span class="token punctuation">.</span><span class="token function">supports</span><span class="token punctuation">(</span><span class="token string">'-webkit-column-width'</span><span class="token punctuation">,</span> <span class="token string">'1px'</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token constant">CSS</span><span class="token punctuation">.</span><span class="token function">supports</span><span class="token punctuation">(</span><span class="token string">'-moz-column-width'</span><span class="token punctuation">,</span> <span class="token string">'1px'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br /><span class="token operator">||</span> <span class="token punctuation">(</span>document<span class="token punctuation">.</span>body<span class="token punctuation">.</span>style<span class="token punctuation">.</span>columnWidth <span class="token operator">===</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> document<span class="token punctuation">.</span>documentElement<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">'columns'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>Then I do some width/padding/position updates to the body and containers to prepare them for being a page with height 100vh and scrolling horizontally, as well as adding the column properties to my <code>article</code>. There are also rules set up to try to prevent breaking before a paragraph that follows a heading:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.columns article</span> <span class="token punctuation">{</span><br /> <span class="token comment">/* also include -moz and -webkit */</span><br /> <span class="token property">column-width</span><span class="token punctuation">:</span> 58rem<span class="token punctuation">;</span><br /> <span class="token property">column-gap</span><span class="token punctuation">:</span> 5rem<span class="token punctuation">;</span><br /> <span class="token property">height</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>100vh - 24.5rem<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* take full height less the header and footer */</span><br /><span class="token punctuation">}</span><br /><br /><span class="token selector">.columns p + h3</span> <span class="token punctuation">{</span><br /> <span class="token property">break-after</span><span class="token punctuation">:</span> avoid<span class="token punctuation">;</span> <span class="token comment">/* not well supported outside IE/Edge */</span><br /><span class="token punctuation">}</span></code></pre>
<h3 id="what-were-the-quirks" tabindex="-1">What Were the Quirks? <a class="direct-link" href="https://danielcwilson.com/blog/2015/12/columns/#what-were-the-quirks" aria-hidden="true">#</a></h3>
<p>I had planned to roll this out when I reworked my site a half year ago, but that was when I started using a lot of CodePens in my articles. Columns do not respond well to changes to content once they have rendered (in the case of CodePen a link changes to a module with a different height and different <code>break</code> rules). If the length of your content changes after the column is painted the browsers are not responding to that change, and you will potentially have your last column(s) chopped.</p>
<p>I'd known about this issue since I first tried columns a few years ago... but I still forget about it. I have now learned that both browser resizes and changes to the <code>column</code> properties will cause the browser to repaint, so my current solution is to load the CodePen script and attach an <code>onload</code> event listener. That is still to soon to act, so for now I am resorting to a setTimeout to make it work (in my case a change to the <code>column-gap</code> by .1rem does the trick).</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">function</span> <span class="token function">onCodePenLoad</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">var</span> article <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.post-content'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> article<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">'external-loaded'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//this class just changes the column-gap values by .1rem</span><br /> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token keyword">var</span> cp <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'script'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> cp<span class="token punctuation">.</span>type <span class="token operator">=</span> <span class="token string">'text/javascript'</span><span class="token punctuation">;</span> cp<span class="token punctuation">.</span>async <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span><br /> cp<span class="token punctuation">.</span>src <span class="token operator">=</span> <span class="token string">'//assets.codepen.io/assets/embed/ei.js'</span><span class="token punctuation">;</span><br /> cp<span class="token punctuation">.</span>onload <span class="token operator">=</span> onCodePenLoad<span class="token punctuation">;</span><br /> <span class="token keyword">var</span> s <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementsByTagName</span><span class="token punctuation">(</span><span class="token string">'script'</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span> s<span class="token punctuation">.</span>parentNode<span class="token punctuation">.</span><span class="token function">insertBefore</span><span class="token punctuation">(</span>cp<span class="token punctuation">,</span> s<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h3 id="other-layouts" tabindex="-1">Other Layouts <a class="direct-link" href="https://danielcwilson.com/blog/2015/12/columns/#other-layouts" aria-hidden="true">#</a></h3>
<p>There are many people talking about alternative screen layouts and the new CSS that is here and coming to help us. I highly recommend <a href="http://csslayout.news/">CSS Layout Weekly</a> from Rachel Andrew and catching up on podcasts and talks from Jen Simmons of <a href="http://thewebahead.net/">The Web Ahead</a>.</p>
<p>Should be a fun time ahead on the web.</p>
Web Animations API Tutorial Conclusion2015-09-14T00:00:00Zhttps://danielcwilson.com/blog/2015/09/animations-conclusion/<p class="preamble">This is the conclusion to an <a href="https://danielcwilson.com/tags/web-animations-api">introductory/tutorial series on the Web Animations API</a> coming to browsers. I've updated the series content in June 2016, as Chrome and Firefox have both rolled out major updates (and some small spec changes). If you have thoughts/questions or see that I’ve misinterpreted the spec, please reach out to me on Twitter, <a href="https://twitter.com/dancwilson">@dancwilson</a>.</p>
<p>We've covered a fair amount of ground and hopefully cleared up questions about what the Web Animations API is (and is not). To conclude this series, we'll recap what we've discussed and take a look at what has yet to be implemented.</p>
<h3 id="why-bother-with-the-api" tabindex="-1">Why Bother with the API? <a class="direct-link" href="https://danielcwilson.com/blog/2015/09/animations-conclusion/#why-bother-with-the-api" aria-hidden="true">#</a></h3>
<p>In the <a href="https://danielcwilson.com/blog/2015/07/animations-intro/">introduction</a> we discussed how the API came into being as a way to unite the various methods to animate in CSS, JS, and SVG... with the intent to take the best of them all. This means, for example, JavaScript can latch on to the hardware acceleration that CSS has had for years, and you are not limited to the declarative nature of CSS. The API is not meant to replace libraries like <a href="http://greensock.com/">GSAP</a>, but simply to provide more options at the browser level.</p>
<p><a href="https://birtles.github.io/areweanimatedyet/">Firefox</a> and <a href="https://www.chromestatus.com/features#animations">Chrome</a> have both started implementations, and Edge has it <a href="https://dev.modern.ie/platform/status/webanimationsjavascriptapi/">on its backlog</a>. The <a href="https://github.com/web-animations/web-animations-js">polyfill</a> allows us to start playing with it today as the team finalizes the <a href="https://w3c.github.io/web-animations/">specification</a>.</p>
<h3 id="animation-basics" tabindex="-1">Animation Basics <a class="direct-link" href="https://danielcwilson.com/blog/2015/09/animations-conclusion/#animation-basics" aria-hidden="true">#</a></h3>
<p>To <a href="https://danielcwilson.com/blog/2015/07/animations-part-1/">create a basic animation</a>, we follow a structure similar to CSS by providing keyframes and timing properties.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">var</span> player <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'toAnimate'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">animate</span><span class="token punctuation">(</span><span class="token punctuation">[</span><br /> <span class="token punctuation">{</span> <span class="token literal-property property">transform</span><span class="token operator">:</span> <span class="token string">'scale(1)'</span><span class="token punctuation">,</span> <span class="token literal-property property">opacity</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token literal-property property">offset</span><span class="token operator">:</span> <span class="token number">0</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token punctuation">{</span> <span class="token literal-property property">transform</span><span class="token operator">:</span> <span class="token string">'scale(.6)'</span><span class="token punctuation">,</span> <span class="token literal-property property">opacity</span><span class="token operator">:</span> <span class="token number">.6</span><span class="token punctuation">,</span> <span class="token literal-property property">offset</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><br /><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br /> <span class="token literal-property property">duration</span><span class="token operator">:</span> <span class="token number">700</span><span class="token punctuation">,</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p><a href="https://danielcwilson.com/blog/2015/07/animations-part-2/">Timeline controls</a> are the obvious pieces not currently present in CSS. Reading the state of an animation happens via the <code>playState</code> property, and changing the state is via methods such as <code>play()</code>, <code>pause()</code>, and <code>finish()</code>. We can also change the playback rate to be slower or faster with the read/write <code>playbackRate</code> property. The <code>currentTime</code> can be checked (or changed), and we can set a callback for when the animation finishes with <code>onfinish</code>.</p>
<h3 id="multiple-animations-and-grouping" tabindex="-1">Multiple Animations and Grouping <a class="direct-link" href="https://danielcwilson.com/blog/2015/09/animations-conclusion/#multiple-animations-and-grouping" aria-hidden="true">#</a></h3>
<p>The Web Animations API allows for <a href="https://danielcwilson.com/blog/2015/08/animations-part-3">multiple animations on an element</a>, creating separate animation objects. The default timeline on the <code>document</code> gives us access to all animations created with the <code>getAnimations()</code> method. Animations can be grouped to play together or one after the other by <a href="https://danielcwilson.com/blog/2015/09/animations-part-4">using GroupEffects and SequenceEffects</a> (available in the polyfill but not in the first spec).</p>
<h3 id="motion-path-and-the-future" tabindex="-1">Motion Path and the Future <a class="direct-link" href="https://danielcwilson.com/blog/2015/09/animations-conclusion/#motion-path-and-the-future" aria-hidden="true">#</a></h3>
<p><a href="https://danielcwilson.com/blog/2015/09/animations-part-5">Animating along a path</a> sneakily saw its first implementation in CSS during this series, but there are many other pieces yet to come.</p>
<h4 id="spacing" tabindex="-1">Spacing <a class="direct-link" href="https://danielcwilson.com/blog/2015/09/animations-conclusion/#spacing" aria-hidden="true">#</a></h4>
<p>The current implementations use a default spacing if no <code>offset</code>s are set in the keyframes, meaning they are evenly distributed (e.g. three frames will have offsets of 0, .5, and 1). The specification also defines a way to pace the animation based on a property, so that it has a constant rate of change. The spec describes this well when discussing <a href="http://w3c.github.io/web-animations/#spacing-keyframes">Spacing Keyframes</a>.</p>
<h4 id="promises" tabindex="-1">Promises <a class="direct-link" href="https://danielcwilson.com/blog/2015/09/animations-conclusion/#promises" aria-hidden="true">#</a></h4>
<p>The spec has evolved to include a <code>ready</code> Promise that will be replaced with a new Promise every time the animation is cancelled or enters a pending state (which will typically happen before changing to "running" or "paused"). In addition to using the <code>onfinish</code> callback as we have discussed in this series, we will be able to use the <code>finished</code> Promise to run a function after an animation finishes.</p>
<h3 id="let's-keep-talking-about-the-web-animations-api" tabindex="-1">Let's Keep Talking about the Web Animations API <a class="direct-link" href="https://danielcwilson.com/blog/2015/09/animations-conclusion/#let's-keep-talking-about-the-web-animations-api" aria-hidden="true">#</a></h3>
<p>People are starting to talk more about this API, and I hope this conversation continues. The spec, browser implementations, and polyfill have been going on for a while, and they are ready to examine closely.</p>
<p>Sometimes CSS will make the most sense, sometimes <code>requestAnimationFrame</code> will, and sometimes using a library will be the best solution. It's good to know when to use what, and this API provides quite a few things that were not previously available to us by default... so have fun.</p>
<p>Check out the rest of this series:</p>
<ul>
<li><a href="https://danielcwilson.com/blog/2015/07/animations-intro">Introduction</a></li>
<li><a href="https://danielcwilson.com/blog/2015/07/animations-part-1">Part 1: Creating a Basic Animation</a></li>
<li><a href="https://danielcwilson.com/blog/2015/07/animations-part-2">Part 2: The Animation and Timeline Controls</a></li>
<li><a href="https://danielcwilson.com/blog/2015/08/animations-part-3">Part 3: Multiple Animations</a></li>
<li><a href="https://danielcwilson.com/blog/2015/09/animations-part-4">Part 4: GroupEffects and SequenceEffects</a></li>
<li><a href="https://danielcwilson.com/blog/2015/09/animations-part-5">Part 5: Motion Paths</a></li>
</ul>
Web Animations API Tutorial Part 5: The Loveable Motion Path2015-09-08T00:00:00Zhttps://danielcwilson.com/blog/2015/09/animations-part-5/<p class="preamble">This is Part 5 of an <a href="https://danielcwilson.com/tags/web-animations-api">introductory/tutorial series on the Web Animations API</a> coming to browsers. The spec (and Chromium implementation) for Motion Path has changed significantly since this article was written. The following is still valid conceptually, but property names and more have changed. For the latest, please check <a href="https://codepen.io/danwilson/post/css-motion-paths-2016">CSS Motion Path as of October 2016</a>.</p>
<p>Finally. Animating along a path... no longer just the domain of SVG.</p>
<h3 id="motion-path:-current-direction-(of-the-spec)" tabindex="-1">Motion Path: Current Direction (of the Spec) <a class="direct-link" href="https://danielcwilson.com/blog/2015/09/animations-part-5/#motion-path:-current-direction-(of-the-spec)" aria-hidden="true">#</a></h3>
<p data-height="145" data-theme-id="0" data-slug-hash="MwLmby" data-default-tab="result" data-user="danwilson" class="codepen">See the Pen <a href="http://codepen.io/danwilson/pen/MwLmby/">Motion Path Infinity</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<p>As the API specification has been worked through, motion path has appeared in different forms. One direction that initially seemed likely was the form of an <a href="https://github.com/w3c/web-animations/commit/e0e116e31960033beccc67b9a5047cfcb0b0f92a">Effect</a> (like the <a href="https://danielcwilson.com/blog/2015/09/animations-part-4">previously discussed GroupEffect</a>), but then a little bit of steam picked up with Motion Path as a CSS Module (with <a href="http://www.w3.org/TR/motion-1/">its own spec</a>).</p>
<p>Therefore animating along a path will simply be another set of CSS properties that can be animated, just as <code>opacity</code> and <code>tranform</code> can. This way CSS Transitions and Keyframes can use it as well as the Web Animations API... which is great since we want as much as we can shared between these methods to give us more flexibility. Chrome and Opera have released an initial implementation, so we can actually start playing with it today even though it has not found its way to any polyfill.</p>
<p>Let's break down what these properties are, how we can use them, and what things might still trip us up for now.</p>
<h3 id="motion-path-properties" tabindex="-1">Motion Path Properties <a class="direct-link" href="https://danielcwilson.com/blog/2015/09/animations-part-5/#motion-path-properties" aria-hidden="true">#</a></h3>
<p>There are three <code>motion</code> properties we will discuss. For now, to see the examples you will need to be running Chrome 46 or Opera 33.</p>
<h4 id="motion-path" tabindex="-1"><code>motion-path</code> <a class="direct-link" href="https://danielcwilson.com/blog/2015/09/animations-part-5/#motion-path" aria-hidden="true">#</a></h4>
<p>The starting point is <code>motion-path</code> which defines a path along which the element can move, following how paths work in SVG 1.1:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">#motioner</span> <span class="token punctuation">{</span><br /> <span class="token property">motion-path</span><span class="token punctuation">:</span> <span class="token function">path</span><span class="token punctuation">(</span><span class="token string">"M200 200 S 200.5 200.1 348.7 184.4z"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>This can also take a <code>fill-rule</code> as an optional first parameter in the path call. I recommend reading <a href="http://svgpocketguide.com/book/#section-4">Joni Trythall’s excellent Pocket Guide to Writing SVG</a> for a discussion on what this entails.</p>
<p>According to the spec, you can also use a basic shape such as <code>circle</code>, <code>polygon</code>, <code>ellipse</code>, and <code>inset</code>. These should look familiar to you if you have tried using <a href="http://alistapart.com/article/css-shapes-101">CSS Shapes</a>.</p>
<p>With Blink's initial implementation, I've only seen the <code>path()</code> method work, so either I've been using shapes incorrectly or that is yet to come.</p>
<h4 id="motion-offset" tabindex="-1"><code>motion-offset</code> <a class="direct-link" href="https://danielcwilson.com/blog/2015/09/animations-part-5/#motion-offset" aria-hidden="true">#</a></h4>
<p>To drive the motion and actually place the element somewhere on the path we use <code>motion-offset</code>. This can either be a double length value or a percentage. So to animate from the starting point of the path to the end we set up an animation that goes from 0 to 100%. With the Web Animations API we have</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">var</span> m <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'motioner'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />m<span class="token punctuation">.</span><span class="token function">animate</span><span class="token punctuation">(</span><span class="token punctuation">[</span><br /> <span class="token punctuation">{</span> <span class="token literal-property property">motionOffset</span><span class="token operator">:</span> <span class="token number">0</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token punctuation">{</span> <span class="token literal-property property">motionOffset</span><span class="token operator">:</span> <span class="token string">'100%'</span> <span class="token punctuation">}</span><br /><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>And with CSS</p>
<pre class="language-css"><code class="language-css"><span class="token selector">#motioner</span> <span class="token punctuation">{</span><br /><span class="token property">animation</span><span class="token punctuation">:</span> path-animation 1s<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token atrule"><span class="token rule">@keyframes</span> path-animation</span> <span class="token punctuation">{</span><br /> <span class="token selector">0%</span> <span class="token punctuation">{</span><br /> <span class="token property">motion-offset</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token selector">100%</span> <span class="token punctuation">{</span><br /> <span class="token property">motion-offset</span><span class="token punctuation">:</span> <span class="token string">'100%'</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span></code></pre>
<p data-height="425" data-theme-id="0" data-slug-hash="ZGmeRO" data-default-tab="result" data-user="danwilson" class="codepen">See the Pen <a href="http://codepen.io/danwilson/pen/ZGmeRO/">CSS Motion Path Spiral</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<p>This CodePen demo shows several dots moving along a spiral path from the outside to the inside. As each dot approaches the center it gets faster, smaller, and becomes transparent. <code>.animate()</code> is called twice on each dot with inifinite iterations and a delay, where one call focuses on the motion offset and the other focuses on the scaling and opacity. I broke them out to specify different easings, but they certainly could have been combined.</p>
<p>This approach also uses feature detection, which you will notice if you are viewing this in Safari, Firefox, Edge, or an older Chrome/Opera because you will see a message instead of the animation. There a few ways to do this, such as</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">var</span> m <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'motioner'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">if</span> <span class="token punctuation">(</span>m<span class="token punctuation">.</span>style<span class="token punctuation">.</span>motionOffset <span class="token operator">!==</span> <span class="token keyword">undefined</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span></code></pre>
<p>Of course, we wouldn't want to block out users completely in a real <a href="https://adactio.com/journal/6246">web thang</a>, so we can have an alternate animation (or no animation) that switches to the Motion Path animation if supported. Progressive Enhancement is a friend here, as usual.</p>
<h4 id="motion-rotation" tabindex="-1"><code>motion-rotation</code> <a class="direct-link" href="https://danielcwilson.com/blog/2015/09/animations-part-5/#motion-rotation" aria-hidden="true">#</a></h4>
<p>The final property is <code>motion-rotation</code>, and it deals with which direction the element "faces" as it moves along the path. There are four primary ways to specify this.</p>
<ul>
<li>The value "auto" means the element will rotate with the path.</li>
<li>With the value "reverse" the element will also rotate with the path, but it will add 180 degress, so it will be facing backward.</li>
<li>"auto Xdeg" (or "reverse Xdeg") will do the same except add X degrees</li>
<li>"Xdeg" will no longer rotate with the path, the element will stay fixed facing the same direction.</li>
</ul>
<p data-height="350" data-theme-id="0" data-slug-hash="qdLQjz" data-default-tab="result" data-user="danwilson" class="codepen">See the Pen <a href="http://codepen.io/danwilson/pen/qdLQjz/">CSS MotionPath</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<h3 id="what's-missing" tabindex="-1">What's Missing? <a class="direct-link" href="https://danielcwilson.com/blog/2015/09/animations-part-5/#what's-missing" aria-hidden="true">#</a></h3>
<p>This is a first version, of course, and the browser makers and spec writers are still discussing it all. The biggest thing I have noticed while trying this out was the lack of a way to adapt the path to different screen/container sizes.</p>
<p>Paths simply appear as they are defined. When working with SVG we get flexibility because we have different coordinate systems and attributes on the container like <a href="http://sarasoueidan.com/blog/svg-coordinate-systems/#svg-viewbox">viewBox</a>. With Motion Paths defined in CSS, the size of the path cannot be additionally modified or constrained with other properties. The width and height defined on your element apply only to the element, not its motion path. You could use media queries or JavaScript to define different paths for different criteria, but setting it up with flexibility via the <code>motion</code> properties is not possible yet.</p>
<h3 id="wrap-up-and-next-time" tabindex="-1">Wrap Up and Next Time <a class="direct-link" href="https://danielcwilson.com/blog/2015/09/animations-part-5/#wrap-up-and-next-time" aria-hidden="true">#</a></h3>
<p>We will see the direction the specification takes, but for now it's fun to try this out and see what it might provide (and not provide). I'm gathering a <a href="http://codepen.io/collection/AQWaem">collection of CSS Motion Path demos</a> I find on CodePen, and Eric Willigers (owner of this implementation task on the Chrome development team) has a <a href="https://docs.google.com/document/d/15nn0tc9meyahzSBAauYtIUpGFsuHaieZt403k1v9B90/edit">Google Doc with examples</a>.</p>
<p>We will wrap up this series next time by recapping what we have discussed and taking a look at a few currently-only-in-the-spec topics.</p>
<p>Check out the rest of this series:</p>
<ul>
<li><a href="https://danielcwilson.com/blog/2015/07/animations-intro">Introduction</a></li>
<li><a href="https://danielcwilson.com/blog/2015/07/animations-part-1">Part 1: Creating a Basic Animation</a></li>
<li><a href="https://danielcwilson.com/blog/2015/07/animations-part-2">Part 2: The Animation and Timeline Controls</a></li>
<li><a href="https://danielcwilson.com/blog/2015/08/animations-part-3">Part 3: Multiple Animations</a></li>
<li><a href="https://danielcwilson.com/blog/2015/09/animations-part-4">Part 4: GroupEffects and SequenceEffects</a></li>
<li><a href="https://danielcwilson.com/blog/2015/09/animations-conclusion">Conclusion</a></li>
</ul>
Web Animations API Tutorial Part 4: GroupEffects & SequenceEffects2015-09-02T00:00:00Zhttps://danielcwilson.com/blog/2015/09/animations-part-4/<p class="preamble">This is Part 4 of an <a href="https://danielcwilson.com/tags/web-animations-api">introductory/tutorial series on the Web Animations API</a> coming to browsers. I've updated the series content in June 2016, as Chrome and Firefox have both rolled out major updates (and some small spec changes). If you have thoughts/questions or see that I’ve misinterpreted the spec, please reach out to me on Twitter, <a href="https://twitter.com/dancwilson">@dancwilson</a>.</p>
<p>Let's continue our discussion on <a href="https://danielcwilson.com/blog/2015/08/animations-part-3">multiple animations</a> within the Web Animations API by discussing a few pieces available today in the polyfill to provide grouping and sequencing.</p>
<h3 id="keyframeeffects" tabindex="-1">KeyframeEffects <a class="direct-link" href="https://danielcwilson.com/blog/2015/09/animations-part-4/#keyframeeffects" aria-hidden="true">#</a></h3>
<p>A <code>KeyframeEffect</code> takes three parameters: the element to animate, an array of keyframes, and our timing options. These are all parameters we've seen before when using <code>element.animate()</code>. This new object essentially is a blueprint for a single animation and we will see it as we discuss ways to group and sequence animations. It does not start an animation, it just defines one.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">var</span> elem <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'toAnimate'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">var</span> timings <span class="token operator">=</span> <span class="token punctuation">{</span><br /> <span class="token literal-property property">duration</span><span class="token operator">:</span> <span class="token number">1000</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">fill</span><span class="token operator">:</span> <span class="token string">'both'</span><br /><span class="token punctuation">}</span><br /><span class="token keyword">var</span> keyframes <span class="token operator">=</span> <span class="token punctuation">[</span><br /> <span class="token punctuation">{</span> <span class="token literal-property property">opacity</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">.</span><br /> <span class="token punctuation">{</span> <span class="token literal-property property">opacity</span><span class="token operator">:</span> <span class="token number">0</span> <span class="token punctuation">}</span><br /><span class="token punctuation">]</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">var</span> effect <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">KeyframeEffect</span><span class="token punctuation">(</span>elem<span class="token punctuation">,</span> keyframes<span class="token punctuation">,</span> timings<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h3 id="groupeffects" tabindex="-1">GroupEffects <a class="direct-link" href="https://danielcwilson.com/blog/2015/09/animations-part-4/#groupeffects" aria-hidden="true">#</a></h3>
<p>Though not available in any native implementation yet, and not even found in the <a href="https://w3c.github.io/web-animations/">Level 1 spec</a>, the <a href="https://github.com/web-animations/web-animations-js">polyfill</a> provides a way to group animations and play them together. The <code>GroupEffect</code> (yes, <a href="https://twitter.com/rachelnabors/status/631545063965720576">it is coming</a> in the Level 2 spec) groups one or more <code>KeyframeEffect</code>s to play simultaneously.</p>
<p data-height="268" data-theme-id="0" data-slug-hash="zGeVey" data-default-tab="result" data-user="danwilson" class="codepen">See the Pen <a href="http://codepen.io/danwilson/pen/zGeVey/">zGeVey</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<p>A <code>GroupEffect</code> takes an effects parameter where we can pass in our array of <code>KeyframeEffect</code>s representing our multiple animations. Once defined, we can play the group of animations on the default timeline when ready.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">var</span> elem <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'toAnimate'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">var</span> elem2 <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'toAnimate2'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">var</span> timings <span class="token operator">=</span> <span class="token punctuation">{</span><br /> <span class="token literal-property property">duration</span><span class="token operator">:</span> <span class="token number">1000</span><br /><span class="token punctuation">}</span><br /><span class="token keyword">var</span> keyframes <span class="token operator">=</span> <span class="token punctuation">[</span><br /> <span class="token punctuation">{</span> <span class="token literal-property property">opacity</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">.</span><br /> <span class="token punctuation">{</span> <span class="token literal-property property">opacity</span><span class="token operator">:</span> <span class="token number">0</span> <span class="token punctuation">}</span><br /><span class="token punctuation">]</span><span class="token punctuation">;</span><br /><br /><span class="token keyword">var</span> kEffects <span class="token operator">=</span> <span class="token punctuation">[</span><br /> <span class="token keyword">new</span> <span class="token class-name">KeyframeEffect</span><span class="token punctuation">(</span>elem<span class="token punctuation">,</span> keyframes<span class="token punctuation">,</span> timings<span class="token punctuation">)</span><span class="token punctuation">,</span><br /> <span class="token keyword">new</span> <span class="token class-name">KeyframeEffect</span><span class="token punctuation">(</span>elem2<span class="token punctuation">,</span> keyframes<span class="token punctuation">,</span> timings<span class="token punctuation">)</span><br /><span class="token punctuation">]</span><span class="token punctuation">;</span><br /><span class="token keyword">var</span> group <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">GroupEffect</span><span class="token punctuation">(</span>kEffects<span class="token punctuation">)</span><span class="token punctuation">;</span><br />document<span class="token punctuation">.</span>timeline<span class="token punctuation">.</span><span class="token function">play</span><span class="token punctuation">(</span>group<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h3 id="sequenceeffects" tabindex="-1">SequenceEffects <a class="direct-link" href="https://danielcwilson.com/blog/2015/09/animations-part-4/#sequenceeffects" aria-hidden="true">#</a></h3>
<p>Similar to the <code>GroupEffect</code>, <code>SequenceEffect</code>s allow us to group together multiple animations (specified by <code>KeyframeEffect</code>s)... but instead of playing them in parallel they play one after the other. You can also, as defined in the polyfill, use <code>GroupEffect</code> and <code>SequenceEffect</code> together (such as having a grouping of multiple sequences).</p>
<p data-height="268" data-theme-id="0" data-slug-hash="vNYQLL" data-default-tab="result" data-user="danwilson" class="codepen">See the Pen <a href="http://codepen.io/danwilson/pen/vNYQLL/">vNYQLL</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<p>Sequences give you something that we've had to work our way around with CSS or with what we've seen with the animations API so far. We would have to maintain delays based on duration of earlier animations or use <code>finish</code> callbacks. These methods can be hard to maintain and may not be as precise.</p>
<p>Using the earlier variables from the <code>GroupEffect</code> code segment:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">var</span> sequence <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">SequenceEffect</span><span class="token punctuation">(</span>kEffects<span class="token punctuation">)</span><span class="token punctuation">;</span><br />document<span class="token punctuation">.</span>timeline<span class="token punctuation">.</span><span class="token function">play</span><span class="token punctuation">(</span>sequence<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h3 id="an-alternate-way-to-create-an-animation" tabindex="-1">An Alternate Way to Create an Animation <a class="direct-link" href="https://danielcwilson.com/blog/2015/09/animations-part-4/#an-alternate-way-to-create-an-animation" aria-hidden="true">#</a></h3>
<p>We have previously looked at the <code>element.animate()</code> way to create animations. This is the quick way to create an animation, play it immediately, and get a reference to the <code>Animation</code> object. We focused on this first since it has been supported in Chrome for a while now, as well as the polyfill. Firefox is the first to support an alternate way: the <code>Animation</code> constructor. It shows us one more way to use the <code>KeyframeEffect</code>, and it is in the Level 1 spec so we should see more use of this soon.</p>
<p>First a reminder of how <code>element.animate()</code> works:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">var</span> elem <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'toAnimate'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">var</span> timings <span class="token operator">=</span> <span class="token punctuation">{</span><br /> <span class="token literal-property property">duration</span><span class="token operator">:</span> <span class="token number">1000</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">fill</span><span class="token operator">:</span> <span class="token string">'both'</span><br /><span class="token punctuation">}</span><br /><span class="token keyword">var</span> keyframes <span class="token operator">=</span> <span class="token punctuation">[</span><br /> <span class="token punctuation">{</span> <span class="token literal-property property">opacity</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">.</span><br /> <span class="token punctuation">{</span> <span class="token literal-property property">opacity</span><span class="token operator">:</span> <span class="token number">0</span> <span class="token punctuation">}</span><br /><span class="token punctuation">]</span><span class="token punctuation">;</span><br /><br />elem<span class="token punctuation">.</span><span class="token function">animate</span><span class="token punctuation">(</span>keyframes<span class="token punctuation">,</span> timings<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Using the same variables as above, the following is equivalent using the <code>Animation</code> constructor:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">var</span> kEffect <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">KeyframeEffect</span><span class="token punctuation">(</span>elem<span class="token punctuation">,</span> keyframes<span class="token punctuation">,</span> timings<span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">var</span> player <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Animation</span><span class="token punctuation">(</span>kEffect<span class="token punctuation">,</span> elem<span class="token punctuation">.</span>ownerDocument<span class="token punctuation">.</span>timeline<span class="token punctuation">)</span><span class="token punctuation">;</span><br />player<span class="token punctuation">.</span><span class="token function">play</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>The primary difference here is that the animation does not start playing immediately, so this will be useful when creating animations in advance to be played later.</p>
<h3 id="wrap-up-and-next-time" tabindex="-1">Wrap Up and Next Time <a class="direct-link" href="https://danielcwilson.com/blog/2015/09/animations-part-4/#wrap-up-and-next-time" aria-hidden="true">#</a></h3>
<p>As the Level 2 spec makes its way through the working drafts, we should see more definition on these different Effects. There are two more planned posts in this series. Next time we will take a look at the future again with what else we can expect to see soon.</p>
<p>Check out the rest of this series:</p>
<ul>
<li><a href="https://danielcwilson.com/blog/2015/07/animations-intro">Introduction</a></li>
<li><a href="https://danielcwilson.com/blog/2015/07/animations-part-1">Part 1: Creating a Basic Animation</a></li>
<li><a href="https://danielcwilson.com/blog/2015/07/animations-part-2">Part 2: The Animation and Timeline Controls</a></li>
<li><a href="https://danielcwilson.com/blog/2015/08/animations-part-3">Part 3: Multiple Animations</a></li>
<li><a href="https://danielcwilson.com/blog/2015/09/animations-part-5">Part 5: Motion Paths</a></li>
<li><a href="https://danielcwilson.com/blog/2015/09/animations-conclusion">Conclusion</a></li>
</ul>
Tessel + NeoPixels + Web + More2015-08-20T00:00:00Zhttps://danielcwilson.com/blog/2015/08/tessel-neopixels/<p>About a year ago I bought a <a href="https://tessel.io/">Tessel</a> and a few <a href="http://www.adafruit.com/category/168">NeoPixel</a> combinations to start developing beyond the screen. Since I hadn't done any soldering since my Theremin craze, I had to get familiar with that again, but otherwise it was largely straightforward to jump in. I made a few small things like a "wreath" that changed colors depending on what holiday you were currently approaching. There was also what I called a baby monitor that used the <a href="https://tessel.io/modules#module-ambient">ambient module</a> to listen for noise (such as a cry) and fade in a soothing color and then fade it out.</p>
<p>My most recent small project revolves around a light show. My wife wanted to buy something that would cast light against a wall and move it to entertain our son. I suggested we try to build it ourselves with the Tessel, and now I have the <a href="https://github.com/danwilson/tessel-neopixels-monitor">initial version available on GitHub</a>. Yes, we are talking kid eyes, and NeoPixels are <strong>bright</strong>, so it's important to note this is a proof of concept only. The ideal way to do this ultimately would be to put the Tessel and NeoPixels behind an object such as a dresser. That way you are just admiring the glow against the wall.</p>
<p>Here is the current code in action (not behind the dresser, simply to show what the NeoPixels are doing):</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/I9DL99_tx0c" frameborder="0" allowfullscreen=""></iframe>
<p>I'm taking a 60-LED strand of NeoPixels, using the handy <a href="https://github.com/HarleyKwyn/npx">Npx</a> abstraction for working on Tessel, and setting up a 60 frame animation. I divide the strand into sections of ten NeoPixels, assign a different color to each section, and then move them one by one in each frame.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">colorWave</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> c <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">,</span> len <span class="token operator">=</span> <span class="token constant">NEO_LENGTH</span><span class="token punctuation">;</span> c <span class="token operator"><</span> len<span class="token punctuation">;</span> c<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">var</span> anim1 <span class="token operator">=</span> npx<span class="token punctuation">.</span><span class="token function">newAnimation</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> anim1<span class="token punctuation">.</span><span class="token function">setPattern</span><span class="token punctuation">(</span><span class="token function">initialPattern</span><span class="token punctuation">(</span>c<span class="token punctuation">,</span> <span class="token constant">NEO_LENGTH</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> npx<span class="token punctuation">.</span><span class="token function">enqueue</span><span class="token punctuation">(</span>anim1<span class="token punctuation">,</span> <span class="token constant">DELAY</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">function</span> <span class="token function">initialPattern</span><span class="token punctuation">(</span><span class="token parameter">start<span class="token punctuation">,</span> length</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">var</span> ra <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br /> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> start<span class="token punctuation">,</span> l <span class="token operator">=</span> start <span class="token operator">+</span> length<span class="token punctuation">;</span> i <span class="token operator"><</span> l<span class="token punctuation">;</span> <span class="token operator">++</span>i<span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">var</span> imod <span class="token operator">=</span> i <span class="token operator">%</span> length<span class="token punctuation">;</span><br /> <span class="token comment">/* set color based on segments of 10, and push to array */</span><br /> <span class="token punctuation">}</span><br /> <span class="token keyword">return</span> ra<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><br /><span class="token keyword">function</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> iterations<span class="token operator">++</span><span class="token punctuation">;</span><br /> npx<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> <span class="token keyword">if</span> <span class="token punctuation">(</span>iterations <span class="token operator"><</span> <span class="token number">20</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//run this again</span><br /> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token comment">//turn off</span><br /> npx<span class="token punctuation">.</span><span class="token function">enqueue</span><span class="token punctuation">(</span>npx<span class="token punctuation">.</span><span class="token function">newAnimation</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">setAll</span><span class="token punctuation">(</span><span class="token string">'#000000'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> npx<span class="token punctuation">.</span>queue<span class="token punctuation">.</span><span class="token function">pop</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//remove the "OFF" animation for future plays</span><br /> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>The most interesting part was getting a server running so that I could pass commands to it to play and stop. Take a look at the <a href="https://github.com/danwilson/tessel-neopixels-monitor">code on GitHub</a> (and the README) for the example. With these pieces in place I can push this code my Tessel, the animation will queue up, the server will set up, and then I can go to my controller page, press Play, and the light show begins.</p>
<p>That's it for now, but it got me thinking about other projects for parents. What I'd like to do next is also have the Tessel (and ambient module) listen for noise activity and push instances to <a href="http://parse.com/">Parse</a> to chart out those times. The hypothetical use case here being for tracking a baby crying and how many times he or she woke up in the night.</p>
<p>Fitbit for baby. Because parents never remember how many times they got up the previous night.</p>
<p>When I do that I'll post about the process of sending data from the Tessel as well.</p>
Web Animations API Tutorial Part 3: Multiple Animations2015-08-13T00:00:00Zhttps://danielcwilson.com/blog/2015/08/animations-part-3/<p class="preamble">This is Part 3 of an <a href="https://danielcwilson.com/tags/web-animations-api">introductory/tutorial series on the Web Animations API</a> coming to browsers. I've updated the series content in June 2016, as Chrome and Firefox have both rolled out major updates (and some small spec changes). If you have thoughts/questions or see that I’ve misinterpreted the spec, please reach out to me on Twitter, <a href="https://twitter.com/dancwilson">@dancwilson</a>.</p>
<p>After our discussion on <a href="https://danielcwilson.com/blog/2015/07/animations-part-2">the Animation's controls and timelines</a> within the Web Animations API, let’s talk about multiple animations.</p>
<h3 id="multiple-animations-per-element" tabindex="-1">Multiple Animations Per Element <a class="direct-link" href="https://danielcwilson.com/blog/2015/08/animations-part-3/#multiple-animations-per-element" aria-hidden="true">#</a></h3>
<p data-height="268" data-theme-id="0" data-slug-hash="PqxvJo" data-default-tab="result" data-user="danwilson" class="codepen">See the Pen <a href="http://codepen.io/danwilson/pen/PqxvJo/">Multiple animate calls</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<p>In this example, each rectangle has three animations applied (affecting transform, opacity, and color). You can call <code>animate()</code> on an element multiple times, similar to CSS allowing multiple animations.</p>
<p>With CSS:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">#toAnimate</span> <span class="token punctuation">{</span><br /> <span class="token property">animation</span><span class="token punctuation">:</span> pulse 1s<span class="token punctuation">,</span> activate 3000ms<span class="token punctuation">,</span> have-fun-with-it 2.5s<span class="token punctuation">;</span><br /><span class="token punctuation">}</span><br /><span class="token atrule"><span class="token rule">@keyframes</span> pulse</span> <span class="token punctuation">{</span> <span class="token comment">/* ... */</span> <span class="token punctuation">}</span><br /><span class="token atrule"><span class="token rule">@keyframes</span> activate</span> <span class="token punctuation">{</span> <span class="token comment">/* ... */</span> <span class="token punctuation">}</span><br /><span class="token atrule"><span class="token rule">@keyframes</span> have-fun-with-it</span> <span class="token punctuation">{</span> <span class="token comment">/* ... */</span> <span class="token punctuation">}</span></code></pre>
<p>With the Web Animations API:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">var</span> animated <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'toAnimate'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">var</span> pulseKeyframes<span class="token punctuation">,</span> <span class="token comment">//defined the keyframes here.</span><br /> activateKeyframes<span class="token punctuation">,</span><br /> haveFunKeyframes<span class="token punctuation">;</span><br /><span class="token keyword">var</span> pulse <span class="token operator">=</span> animated<span class="token punctuation">.</span><span class="token function">animate</span><span class="token punctuation">(</span>pulseKeyframes<span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//the second parameter as a number is a valid shorthand for duration</span><br /><span class="token keyword">var</span> activate <span class="token operator">=</span> animated<span class="token punctuation">.</span><span class="token function">animate</span><span class="token punctuation">(</span>activateKeyframes<span class="token punctuation">,</span> <span class="token number">3000</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token keyword">var</span> haveFunWithIt <span class="token operator">=</span> animated<span class="token punctuation">.</span><span class="token function">animate</span><span class="token punctuation">(</span>haveFunKeyframes<span class="token punctuation">,</span> <span class="token number">2500</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>With the Web Animations API, this creates three <a href="https://danielcwilson.com/blog/2015/07/animations-part-2">Animation objects</a> that can each be paused, played, finished, canceled, and manipulated via timeline or playback rate.</p>
<h3 id="get-the-animations-get-them-all" tabindex="-1">Get the <code>Animation</code>s, Get Them All <a class="direct-link" href="https://danielcwilson.com/blog/2015/08/animations-part-3/#get-the-animations-get-them-all" aria-hidden="true">#</a></h3>
<p>So you've got an animation kicked off and playing, but you didn't capture the <code>Animation</code> reference when you called <code>animate()</code> on the element. What’s a person to do?</p>
<p data-height="268" data-theme-id="0" data-slug-hash="PqgKVK" data-default-tab="result" data-user="danwilson" class="codepen">See the Pen <a href="http://codepen.io/danwilson/pen/PqgKVK/">PqgKVK</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<p>The spec allows for a method <code>getAnimations()</code> on the document. In the latest version of the spec it is directly on the document (<code>document.getAnimations()</code>) which is how it is implemented in Firefox 48+. However, as of Chrome 52 and the <a href="https://github.com/web-animations/web-animations-js">polyfill</a> (as of v2.2.0), it is implemented according to the old spec which placed it on the new <code>timeline</code> object on the document.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">//If including the polyfill you can use the following</span><br /><span class="token keyword">var</span> animations <span class="token operator">=</span> document<span class="token punctuation">.</span>getAnimations <span class="token operator">?</span> document<span class="token punctuation">.</span><span class="token function">getAnimations</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">:</span> document<span class="token punctuation">.</span>timeline<span class="token punctuation">.</span><span class="token function">getAnimations</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><span class="token comment">//returns array of all active (not finished and not canceled) animations</span></code></pre>
<p>In the CodePen example, you will see several dots moving with random durations, delays, and transforms with an infinite duration. The 'Pause All' button calls <code>getAnimations()</code> and iterates through all the returned players (one for each animation) and pauses each one.</p>
<h3 id="next-time..." tabindex="-1">Next Time… <a class="direct-link" href="https://danielcwilson.com/blog/2015/08/animations-part-3/#next-time..." aria-hidden="true">#</a></h3>
<p>In the next part, we'll look at the different ways a WAAPI animation can be created (because there's more to it than just <code>element.animate</code>). Hint: <code>document.timeline</code> will make more appearances.</p>
<p>Check out the rest of this series:</p>
<ul>
<li><a href="https://danielcwilson.com/blog/2015/07/animations-intro">Introduction</a></li>
<li><a href="https://danielcwilson.com/blog/2015/07/animations-part-1">Part 1: Creating a Basic Animation</a></li>
<li><a href="https://danielcwilson.com/blog/2015/07/animations-part-2">Part 2: The Animation and Timeline Controls</a></li>
<li><a href="https://danielcwilson.com/blog/2015/09/animations-part-4">Part 4: GroupEffects and SequenceEffects</a></li>
<li><a href="https://danielcwilson.com/blog/2015/09/animations-part-5">Part 5: Motion Paths</a></li>
<li><a href="https://danielcwilson.com/blog/2015/09/animations-conclusion">Conclusion</a></li>
</ul>
Web Animations API Tutorial Part 2: The Animation & Timeline Controls2015-07-31T00:00:00Zhttps://danielcwilson.com/blog/2015/07/animations-part-2/<p class="preamble">This is Part 2 of an <a href="https://danielcwilson.com/tags/web-animations-api">introductory/tutorial series on the Web Animations API</a> coming to browsers. I've updated the series content in June 2016, as Chrome and Firefox have both rolled out major updates (and some small spec changes). If you have thoughts/questions or see that I’ve misinterpreted the spec, please reach out to me on Twitter, <a href="https://twitter.com/dancwilson">@dancwilson</a>.</p>
<p>Now that we understand how to <a href="https://danielcwilson.com/blog/2015/07/animations-part-1">create a basic animation</a> with the Web Animations API, let’s talk about states, controls, callbacks, and timelines.</p>
<h3 id="animation-play-states-and-controls" tabindex="-1">Animation Play States and Controls <a class="direct-link" href="https://danielcwilson.com/blog/2015/07/animations-part-2/#animation-play-states-and-controls" aria-hidden="true">#</a></h3>
<p>When you call <code>element.animate()</code>, an <code>Animation</code> object (formerly called an <code>AnimationPlayer</code> in the spec) is returned and the animation starts playing. To see the current state of the animation you can check the readonly property <code>playState</code> which will return one of five strings. We can also modify the current state of the animation, by calling one of four methods:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">var</span> player <span class="token operator">=</span> element<span class="token punctuation">.</span><span class="token function">animate</span><span class="token punctuation">(</span><span class="token comment">/* ... */</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>player<span class="token punctuation">.</span>playState<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//"running"</span><br /><br />player<span class="token punctuation">.</span><span class="token function">pause</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//"paused"</span><br />player<span class="token punctuation">.</span><span class="token function">play</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//"running"</span><br />player<span class="token punctuation">.</span><span class="token function">cancel</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//"idle"... jump to original state</span><br />player<span class="token punctuation">.</span><span class="token function">finish</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//"finished"...jump to end state</span></code></pre>
<p>In addition to <code>running</code>, <code>paused</code>, <code>idle</code>, and <code>finished</code> play states there is a <code>pending</code> state defined that will occur when a play or pause task is pending.</p>
<p>This Walking Circles example shows six circles scaling. You can pause or play each circle to see a portion of the above play states in action.</p>
<p data-height="488" data-theme-id="0" data-slug-hash="WvXRYg" data-default-tab="result" data-user="danwilson" class="codepen">See the Pen <a href="http://codepen.io/danwilson/pen/WvXRYg/">Blob That Walks</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<h3 id="playback-rate" tabindex="-1">Playback Rate <a class="direct-link" href="https://danielcwilson.com/blog/2015/07/animations-part-2/#playback-rate" aria-hidden="true">#</a></h3>
<p>In the previous CodePen example, there is also a "2x" button that you can press to change the playback rate of the animation, switching it to double speed. This is through the read/write <code>playbackRate</code> property.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">var</span> player <span class="token operator">=</span> element<span class="token punctuation">.</span><span class="token function">animate</span><span class="token punctuation">(</span><span class="token comment">/* ... */</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br />console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>player<span class="token punctuation">.</span>playbackRate<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//1</span><br /><br />player<span class="token punctuation">.</span>playbackRate <span class="token operator">=</span> <span class="token number">2</span><span class="token punctuation">;</span> <span class="token comment">//double speed, can also be decimal to slow it down.</span></code></pre>
<h3 id="finish-callback" tabindex="-1">Finish Callback <a class="direct-link" href="https://danielcwilson.com/blog/2015/07/animations-part-2/#finish-callback" aria-hidden="true">#</a></h3>
<p>With CSS transitions, there is an event that typically fires when the transition ends. Similarly, the <code>Animation</code> allows you to specify an <code>onfinish</code> function when the animation either completes or you call the previously discussed <code>finish()</code> method. Note that according to the specification an animation set with an infinite number of iterations cannot be finished, nor can one with a <code>playbackRate</code> of 0. There is also an <code>oncancel</code> handler, and the option of using <a href="https://danielcwilson.com/blog/2016/03/animations-and-promises">Promises</a> for when the <code>Animation</code> finishes.</p>
<p>The following example uses <code>onfinish</code> to display some stats once the animation completes (and it also segues nicely to the next discussion on timelines).</p>
<p data-height="299" data-theme-id="0" data-slug-hash="RPMVZJ" data-default-tab="result" data-user="danwilson" class="codepen">See the Pen <a href="http://codepen.io/danwilson/pen/RPMVZJ/">Timer Countdown</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<h3 id="the-timeline" tabindex="-1">The Timeline <a class="direct-link" href="https://danielcwilson.com/blog/2015/07/animations-part-2/#the-timeline" aria-hidden="true">#</a></h3>
<p>Each <code>Animation</code> exposes two read/write time-related properties - <code>currentTime</code> and <code>startTime</code>. For now, we will focus on the former.</p>
<p><code>currentTime</code> returns the milliseconds where the animation currently is. The max value will be delay + (duration * iterations), so infinite iterations will not have a max value.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">var</span> player <span class="token operator">=</span> element<span class="token punctuation">.</span><span class="token function">animate</span><span class="token punctuation">(</span><span class="token punctuation">[</span><br /> <span class="token punctuation">{</span><span class="token literal-property property">opacity</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">opacity</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">}</span><br /><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br /> <span class="token literal-property property">duration</span><span class="token operator">:</span> <span class="token number">1000</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">delay</span><span class="token operator">:</span> <span class="token number">500</span><span class="token punctuation">,</span><br /> <span class="token literal-property property">iterations</span><span class="token operator">:</span> <span class="token number">3</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br /><br />player<span class="token punctuation">.</span><span class="token function-variable function">onfinish</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br /> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>player<span class="token punctuation">.</span>currentTime<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 3500</span><br /><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>Playback rate will affect how quickly the timeline continues. If you set a playback rate of 10, your max currentTime remains the same, but you will go through the timeline 10 times faster. This concept is also shown in the earlier Timer Countdown example.</p>
<p>Since <code>currentTime</code> is read/write, we can also use this to jump to a certain point in the timeline. It can also let us synchronize two animations, as shown in the next example.</p>
<p data-height="268" data-theme-id="0" data-slug-hash="YXYWKK" data-default-tab="result" data-user="danwilson" class="codepen">See the Pen <a href="http://codepen.io/danwilson/pen/YXYWKK/">Syncing Timelines - WAAPI</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<h3 id="one-more-option:-reverse()" tabindex="-1">One more option: <code>reverse()</code> <a class="direct-link" href="https://danielcwilson.com/blog/2015/07/animations-part-2/#one-more-option:-reverse()" aria-hidden="true">#</a></h3>
<p>You can also reverse an animation with <code>reverse()</code> which will be very similar to <code>play()</code> (such as it will have the same <code>playState</code>) except it will traverse the timeline in reverse. When an animation finishes the <code>currentTime</code> will be 0.</p>
<p data-height="268" data-theme-id="0" data-slug-hash="waRKOm" data-default-tab="result" data-user="danwilson" class="codepen">See the Pen <a href="http://codepen.io/danwilson/pen/waRKOm/">waRKOm</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<h3 id="next-time..." tabindex="-1">Next Time… <a class="direct-link" href="https://danielcwilson.com/blog/2015/07/animations-part-2/#next-time..." aria-hidden="true">#</a></h3>
<p>That was a lot of information, but it was still just getting familiar with what is available. We'll take a look at some more advanced usage next time.</p>
<p>Check out the rest of this series:</p>
<ul>
<li><a href="https://danielcwilson.com/blog/2015/07/animations-intro">Introduction</a></li>
<li><a href="https://danielcwilson.com/blog/2015/07/animations-part-1">Part 1: Creating a Basic Animation</a></li>
<li><a href="https://danielcwilson.com/blog/2015/08/animations-part-3">Part 3: Multiple Animations</a></li>
<li><a href="https://danielcwilson.com/blog/2015/09/animations-part-4">Part 4: GroupEffects and SequenceEffects</a></li>
<li><a href="https://danielcwilson.com/blog/2015/09/animations-part-5">Part 5: Motion Paths</a></li>
<li><a href="https://danielcwilson.com/blog/2015/09/animations-conclusion">Conclusion</a></li>
</ul>
Web Animations API Tutorial Part 1: Creating a Basic Animation2015-07-23T00:00:00Zhttps://danielcwilson.com/blog/2015/07/animations-part-1/<p class="preamble">This is Part 1 of an <a href="https://danielcwilson.com/tags/web-animations-api">introductory/tutorial series on the Web Animations API</a> coming to browsers. I've updated the series content in June 2016, as Chrome and Firefox have both rolled out major updates (and some small spec changes). If you have thoughts/questions or see that I’ve misinterpreted the spec, please reach out to me on Twitter, <a href="https://twitter.com/dancwilson">@dancwilson</a>.</p>
<p>We’ve taken our <a href="https://danielcwilson.com/blog/2015/07/animations-intro">initial look</a> at the Web Animations API, but we didn’t get into any real specifics… so let’s dive in now.</p>
<p>The WAAPI gives you more control than you might be used to with CSS Animations, but before we get into these extras, we need to set up the baseline: How do I create a basic animation through this API?</p>
<h3 id="creating-a-keyframe-animation" tabindex="-1">Creating a Keyframe Animation <a class="direct-link" href="https://danielcwilson.com/blog/2015/07/animations-part-1/#creating-a-keyframe-animation" aria-hidden="true">#</a></h3>
<p>If you are familiar with CSS Transitions and/or animations this will look familiar.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">var</span> player <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'toAnimate'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">animate</span><span class="token punctuation">(</span><span class="token punctuation">[</span><br /> <span class="token punctuation">{</span> <span class="token literal-property property">transform</span><span class="token operator">:</span> <span class="token string">'scale(1)'</span><span class="token punctuation">,</span> <span class="token literal-property property">opacity</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token literal-property property">offset</span><span class="token operator">:</span> <span class="token number">0</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token punctuation">{</span> <span class="token literal-property property">transform</span><span class="token operator">:</span> <span class="token string">'scale(.5)'</span><span class="token punctuation">,</span> <span class="token literal-property property">opacity</span><span class="token operator">:</span> <span class="token number">.5</span><span class="token punctuation">,</span> <span class="token literal-property property">offset</span><span class="token operator">:</span> <span class="token number">.3</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token punctuation">{</span> <span class="token literal-property property">transform</span><span class="token operator">:</span> <span class="token string">'scale(.667)'</span><span class="token punctuation">,</span> <span class="token literal-property property">opacity</span><span class="token operator">:</span> <span class="token number">.667</span><span class="token punctuation">,</span> <span class="token literal-property property">offset</span><span class="token operator">:</span> <span class="token number">.7875</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token punctuation">{</span> <span class="token literal-property property">transform</span><span class="token operator">:</span> <span class="token string">'scale(.6)'</span><span class="token punctuation">,</span> <span class="token literal-property property">opacity</span><span class="token operator">:</span> <span class="token number">.6</span><span class="token punctuation">,</span> <span class="token literal-property property">offset</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><br /><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br /> <span class="token literal-property property">duration</span><span class="token operator">:</span> <span class="token number">700</span><span class="token punctuation">,</span> <span class="token comment">//milliseconds</span><br /> <span class="token literal-property property">easing</span><span class="token operator">:</span> <span class="token string">'ease-in-out'</span><span class="token punctuation">,</span> <span class="token comment">//'linear', a bezier curve, etc.</span><br /> <span class="token literal-property property">delay</span><span class="token operator">:</span> <span class="token number">10</span><span class="token punctuation">,</span> <span class="token comment">//milliseconds</span><br /> <span class="token literal-property property">iterations</span><span class="token operator">:</span> <span class="token number">Infinity</span><span class="token punctuation">,</span> <span class="token comment">//or a number</span><br /> <span class="token literal-property property">direction</span><span class="token operator">:</span> <span class="token string">'alternate'</span><span class="token punctuation">,</span> <span class="token comment">//'normal', 'reverse', etc.</span><br /> <span class="token literal-property property">fill</span><span class="token operator">:</span> <span class="token string">'forwards'</span> <span class="token comment">//'backwards', 'both', 'none', 'auto'</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>For comparison’s sake, here is an equivalent CSS Keyframe animation</p>
<pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@keyframes</span> emphasis</span> <span class="token punctuation">{</span><br /> <span class="token selector">0%</span> <span class="token punctuation">{</span><br /> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">scale</span><span class="token punctuation">(</span>1<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property">opacity</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token selector">30%</span> <span class="token punctuation">{</span><br /> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">scale</span><span class="token punctuation">(</span>.5<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property">opacity</span><span class="token punctuation">:</span> .5<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token selector">78.75%</span> <span class="token punctuation">{</span><br /> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">scale</span><span class="token punctuation">(</span>.667<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property">opacity</span><span class="token punctuation">:</span> .667<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /> <span class="token selector">100%</span> <span class="token punctuation">{</span><br /> <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">scale</span><span class="token punctuation">(</span>.6<span class="token punctuation">)</span><span class="token punctuation">;</span><br /> <span class="token property">opacity</span><span class="token punctuation">:</span> .6<span class="token punctuation">;</span><br /> <span class="token punctuation">}</span><br /><span class="token punctuation">}</span><br /><span class="token selector">#toAnimate</span> <span class="token punctuation">{</span><br /> <span class="token property">animation</span><span class="token punctuation">:</span> emphasis 700ms ease-in-out 10ms infinite alternate forwards<span class="token punctuation">;</span><br /><span class="token punctuation">}</span></code></pre>
<p>We’ll break this down and explain each piece.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">var</span> player <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'toAnimate'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">animate</span><span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre>
<p>Animating will return an <code>Animation</code> (formerly known in the spec as an <code>AnimationPlayer</code>) that will let us do fun things later, so you’ll likely want to set up a variable to capture this reference. We find the element we want to animate (here simply with <code>document.getElementById</code>) and call the <code>animate</code> function. This function is newly added with the spec, so you will either want to test it for support/existence before using it or include the <a href="https://github.com/web-animations/web-animations-js">polyfill</a>.</p>
<p>The <code>animate</code> function takes two parameters, an array of <code>KeyframeEffect</code>s and <code>AnimationEffectTimingProperties</code> options. Essentially the first parameter maps to what you would put in the CSS <code>@keyframes</code>, and the second parameter is what you would specify with the <code>animation-*</code> properties (or the <code>animation</code> shorthand, as in my earlier example) in your CSS rules. The key benefit here is that we can use variables or reuse previously defined <code>KeyframeEffect</code>s, whereas with CSS we’re limited to the values we declare upfront.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">var</span> player <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'toAnimate'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">animate</span><span class="token punctuation">(</span><span class="token punctuation">[</span><br /> <span class="token punctuation">{</span> <span class="token literal-property property">transform</span><span class="token operator">:</span> <span class="token string">'scale(1)'</span><span class="token punctuation">,</span> <span class="token literal-property property">opacity</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token punctuation">{</span> <span class="token literal-property property">transform</span><span class="token operator">:</span> <span class="token string">'scale(.5)'</span><span class="token punctuation">,</span> <span class="token literal-property property">opacity</span><span class="token operator">:</span> <span class="token number">.5</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token punctuation">{</span> <span class="token literal-property property">transform</span><span class="token operator">:</span> <span class="token string">'scale(.667)'</span><span class="token punctuation">,</span> <span class="token literal-property property">opacity</span><span class="token operator">:</span> <span class="token number">.667</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br /> <span class="token punctuation">{</span> <span class="token literal-property property">transform</span><span class="token operator">:</span> <span class="token string">'scale(.6)'</span><span class="token punctuation">,</span> <span class="token literal-property property">opacity</span><span class="token operator">:</span> <span class="token number">.6</span> <span class="token punctuation">}</span><br /><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>For each <code>KeyframeEffect</code>, we change the percentage offsets we have in CSS to a decimal <code>offset</code> value from 0 to 1. It is optional though, and if you don’t specify any they will be evenly distributed (so if you have three, the first has an offset of 0, the second has an offset of .5, and the third offset = 1). You can also specify an <code>easing</code> property that is the same as the <code>animation-timing-function</code> in CSS. The other properties in each <code>KeyframeEffect</code> are the properties to animate. The values for each property should match how you would specify them in JavaScript using <code>element.style</code>, so <code>opacity</code> will be a number, but <code>transform</code> will expect a string.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">var</span> player <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'toAnimate'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">animate</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br /> <span class="token literal-property property">duration</span><span class="token operator">:</span> <span class="token number">700</span><span class="token punctuation">,</span> <span class="token comment">//milliseconds</span><br /> <span class="token literal-property property">easing</span><span class="token operator">:</span> <span class="token string">'ease-in-out'</span><span class="token punctuation">,</span> <span class="token comment">//'linear', a bezier curve, etc.</span><br /> <span class="token literal-property property">delay</span><span class="token operator">:</span> <span class="token number">10</span><span class="token punctuation">,</span> <span class="token comment">//milliseconds</span><br /> <span class="token literal-property property">iterations</span><span class="token operator">:</span> <span class="token number">Infinity</span><span class="token punctuation">,</span> <span class="token comment">//or a number</span><br /> <span class="token literal-property property">direction</span><span class="token operator">:</span> <span class="token string">'alternate'</span><span class="token punctuation">,</span> <span class="token comment">//'normal', 'reverse', etc.</span><br /> <span class="token literal-property property">fill</span><span class="token operator">:</span> <span class="token string">'forwards'</span> <span class="token comment">//'backwards', 'both', 'none', 'auto'</span><br /><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>The timing properties will map to CSS animation properties, though sometimes with different names. The earlier code sample discusses the primary options.</p>
<p>Here is an example that uses the polyfill (but if you are viewing in Chrome 36+, Opera 23+, or Firefox 48+ it should be using the actual browser implementation). The first column grey blocks are animating with the WAAPI, and the second column red blocks are animating with CSS keyframes.</p>
<p data-height="268" data-theme-id="0" data-slug-hash="QwrZwd" data-default-tab="result" data-user="danwilson" class="codepen">See the Pen <a href="http://codepen.io/danwilson/pen/QwrZwd/">CSS Keyframes v. WAAPI</a> by Dan Wilson (<a href="http://codepen.io/danwilson">@danwilson</a>) on <a href="http://codepen.io/">CodePen</a>.</p>
<h3 id="next-time..." tabindex="-1">Next Time… <a class="direct-link" href="https://danielcwilson.com/blog/2015/07/animations-part-1/#next-time..." aria-hidden="true">#</a></h3>
<p>Now that we know how to make an equivalent animation from what we know in CSS, we’ll start looking at the <code>Animation</code> object that the animate function returns. This is where we see the real features and improvements.</p>
<p>Check out the rest of this series:</p>
<ul>
<li><a href="https://danielcwilson.com/blog/2015/07/animations-intro">Introduction</a></li>
<li><a href="https://danielcwilson.com/blog/2015/07/animations-part-2">Part 2: The Animation and Timeline Controls</a></li>
<li><a href="https://danielcwilson.com/blog/2015/08/animations-part-3">Part 3: Multiple Animations</a></li>
<li><a href="https://danielcwilson.com/blog/2015/09/animations-part-4">Part 4: GroupEffects and SequenceEffects</a></li>
<li><a href="https://danielcwilson.com/blog/2015/09/animations-part-5">Part 5: Motion Paths</a></li>
<li><a href="https://danielcwilson.com/blog/2015/09/animations-conclusion">Conclusion</a></li>
</ul>
<script>
// if (document.querySelector) {
// var title = document.querySelector('.post h1');
// if (title && title.animate) {
// letters = title.textContent;
// if (letters && letters.length) {
// var newContent = '';
// for (var i = 0, len = letters.length; i < len; ++i) {
// newContent = newContent + '<span>' + letters[i] + '</span>';
// }
// title.innerHTML = newContent;
// var chars = title.querySelectorAll('span');
// for (var j = 0, len = chars.length; j < len; j = Math.floor(j + (Math.random() * 6 + 1))) {
// if (chars[j]) {
// chars[j].animate([
// {opacity: 1},
// {opacity: .4}
// ], {
// delay: 2000 * (Math.random()),
// easing: 'ease-in-out',
// duration: 3000 * (Math.random() + 1),
// fill: 'both',
// direction: 'alternate',
// iterations: 5
// });
// }
// }
// }
// }
// }
</script>
Let's Talk about the Web Animations API2015-07-20T00:00:00Zhttps://danielcwilson.com/blog/2015/07/animations-intro/<svg id="lets-talk-anim" viewBox="24 19 518 128" style="margin-bottom: 3rem;">
<rect stroke="#e58481" width="120" height="65" fill="transparent" stroke-width="5" x="130" y="22" rx="8" ry="8"></rect>
<text fill="#444" x="25" y="70" font-family="'Helvetica Neue', Helvetica, sans-serif" font-weight="900" font-size="40" textLength="91">Let’s</text>
<text fill="#e58481" x="141" y="72" font-family="'Helvetica Neue', Helvetica, sans-serif" font-weight="900" font-size="55" textLength="96">talk</text>
<text fill="#444" x="261" y="70" font-family="'Helvetica Neue', Helvetica, sans-serif" font-weight="900" font-size="40" textLength="278">about the Web</text>
<text fill="#444" x="25" y="145" font-family="'Helvetica Neue', Helvetica, sans-serif" font-weight="900" font-size="71" textLength="516">Animations API</text>
</svg>
<p class="preamble">This is an introduction to a <a href="https://danielcwilson.com/tags/web-animations-api">tutorial series on the Web Animations API</a> coming to browsers. I've updated the series content in June 2016, as Chrome and Firefox have both rolled out major updates (and some small spec changes). If you have thoughts/questions or see that I’ve misinterpreted the spec, please reach out to me on Twitter, <a href="https://twitter.com/dancwilson">@dancwilson</a>.</p>
<p>In Summer 2014, Google announced Material design with a representation in web through <a href="https://www.polymer-project.org/0.5/platform/web-animations.html">Polymer</a>... using a polyfill for the upcoming standard Web Animations API.</p>
<p>I hadn't heard of this API, but I was intrigued, especially since it talked about a MotionPath effect. That wasn't implemented yet (you'll find out what happened in <a href="https://danielcwilson.com/blog/2015/09/animations-part-5">Part 5</a>), but its goal of providing a way to unite the CSS, JS, and SVG ways to animate kept me interested. A year later and Chrome and Firefox have started implementations, the polyfill's progress is steady, and it's time to take a look at it in earnest.</p>
<p>But so few people are talking about the WAAPI! My hope is to start a series of posts highlighting the features that are in browsers (and the <a href="https://github.com/web-animations/web-animations-js">polyfill</a>) now, exploring why we want this API, and figuring out the nuances. Hopefully we will also get more people discussing, and working with, this API.</p>
<h3 id="what-is-the-web-animations-api" tabindex="-1">What is the Web Animations API? <a class="direct-link" href="https://danielcwilson.com/blog/2015/07/animations-intro/#what-is-the-web-animations-api" aria-hidden="true">#</a></h3>
<p>We'll start this exploration by figuring out what it is and what it is trying to accomplish.</p>
<p>Animation has progressed nicely in the last half decade, with great CSS support and new additions to improve JavaScript. But each approach to animation still has a slew of cons to all the pros they provide.</p>
<ul>
<li>CSS has hardware acceleration for smooth transitions and support is built into the browser, but rules are declared in CSS and require jumping through JavaScript hoops to get values dynamically changed.</li>
<li><code>requestAnimationFrame</code> has good support and lets the browser optimize when to animate, but it can still hang up if there is a lot of other JavaScript running. It also often requires more math to get timing down.</li>
<li><code>setInterval</code> introduced many developers to animations, but it is imprecise and can lead to stuttering animations.</li>
<li><code>jQuery.animate()</code> introduced several other developers to animations, but often has performance issues.</li>
<li>Libraries such as <a href="http://julian.com/research/velocity/">Velocity</a> and <a href="http://greensock.com/">GreenSock (GSAP)</a> improve JavaScript performance and have been tested in many situations to be the best they can be. They still, however, require maintaining and loading external libraries.</li>
</ul>
<p>In general, we like it when browsers support as much as they can, and they take over the optimizations. Browsers now have <code>document.querySelector</code> because we saw the value jQuery provided to select DOM elements. So utilities in libraries moved into the browser natively. Ideally, we could pack as much animation control at the browser level. These libraries can then focus on providing newer features, and the cycle can continue.</p>
<p>The Web Animations API tries to do this. It aims to bring the power of CSS performance, add the benefits and flexibility of JavaScript (and SVG animation, which we will talk about in a future post), and leave it to the browsers to make it work well.</p>
<h3 id="let's-solve-this-by-adding-something-new!" tabindex="-1">Let's solve this by adding something new! <a class="direct-link" href="https://danielcwilson.com/blog/2015/07/animations-intro/#let's-solve-this-by-adding-something-new!" aria-hidden="true">#</a></h3>
<p>At a former job, we received an email stating that they knew we had too many places to check for company announcements - email, monitors in the office, Yammer, Google Chat, and a intranet/wiki. So to solve the problem they announced... they were adding a blog.</p>
<p>My first thought hearing about the Web Animations API was the same thought I had hearing my company was adding a blog - this will only make things worse. Sure enough, the blog didn't centralize anything, it just added one more place we had to check for news, and it died out.</p>
<p>This feels different, though. <a href="https://w3c.github.io/web-animations/">Reviewing a spec</a> (first time I've really done it to this extent) shows the attention put into this. It's not meant to replace existing behaviors (although <a href="https://www.chromestatus.com/features/5371475380928512">some browsers are deprecating some</a> it seems...), but instead unite the various ways and allow them even to interact. The syntax is similar to CSS but adds the options of variables, controls, and finish callbacks.</p>
<h3 id="next-time..." tabindex="-1">Next Time... <a class="direct-link" href="https://danielcwilson.com/blog/2015/07/animations-intro/#next-time..." aria-hidden="true">#</a></h3>
<p>So the Web Animations API is new, and starting to be implemented (currently in <a href="https://www.chromestatus.com/features#animations">Chrome</a> and <a href="https://birtles.github.io/areweanimatedyet/">Firefox</a>) in addition to having a polyfill. Next time we will actually start looking at what it provides developers... with examples!</p>
<p>Check out the rest of this series:</p>
<ul>
<li><a href="https://danielcwilson.com/blog/2015/07/animations-part-1">Part 1: Creating a Basic Animation</a></li>
<li><a href="https://danielcwilson.com/blog/2015/07/animations-part-2">Part 2: The Animation and Timeline Controls</a></li>
<li><a href="https://danielcwilson.com/blog/2015/08/animations-part-3">Part 3: Multiple Animations</a></li>
<li><a href="https://danielcwilson.com/blog/2015/09/animations-part-4">Part 4: GroupEffects and SequenceEffects</a></li>
<li><a href="https://danielcwilson.com/blog/2015/09/animations-part-5">Part 5: Motion Paths</a></li>
<li><a href="https://danielcwilson.com/blog/2015/09/animations-conclusion">Conclusion</a></li>
</ul>
<script>
var svg = document.getElementById('lets-talk-anim');
if (svg) {
svg.style.marginBottom = '3rem';
if (document.querySelectorAll) {
document.querySelector('.post h1').style.display = 'none';
var words = svg.querySelectorAll('text');
if (words && words.length && words[0].animate) {
for (var i = 0, len = words.length; i < len; ++i) {
words[i].animate([
{opacity: 0},
{opacity: 1}
], {
delay: i * 300,
easing: 'ease-in-out',
duration: 1000,
fill: 'both'
});
}
svg.querySelector('rect').animate([
{opacity: 0},
{opacity: .8},
{opacity: .4},
{opacity: .9},
{opacity: 0},
{opacity: 1},
{opacity: 0}
], {
delay: 200,
easing: 'ease-in-out',
duration: 6400,
fill: 'both',
iterations: Infinity
});
}
}
}
</script>
How Many Days Since?2015-06-29T00:00:00Zhttps://danielcwilson.com/blog/archives/63/<p>I looked online. I found a few sites that did what I wanted. None of them worked well on mobile.</p>
<p>I wanted to know how many days it had been since a given date... so here it is: <a href="http://danielcwilson.com/day">How Many Days Since?</a>. It's not fancy. It only has one page. But it does what I needed on all my devices... including using pushState to make the URL bookmarkable.</p>
<p>Sometimes a need is simply something a first semester web student can do. But I wanted one with a little bit of style, so with just a quick CodePen and a push to my server I now have one that suits my exact need... and maybe yours, too.</p>
<p>A well respected web developer has been quoted as saying, “This is the best one of these on the internet!”</p>
20152015-05-16T00:00:00Zhttps://danielcwilson.com/blog/archives/60/<p>Facebook is for seeing photos of strangers' kids and pets that my friends have liked.</p>
<p>Twitter is for seeing people talk about the Apple Watch.</p>
<p>Flipboard's Daily Edition is for finding depressing news. And a fun gif at the end.</p>
<p>Yahoo News Digest is for finding more depressing news. And a fun quote or stat at the end.</p>
<p>LinkedIn is for recruiters to still associate me as a Java developer.</p>
<p>Notifications only exist to disable.</p>
<p>GitHub is for people to wonder why I haven't responded to their comment and threaten to no longer use my plugin.</p>
<p>The Texas grocery store freezer section is for people to write prayers for a company that has recalled its ice cream.</p>
<p>My iPhone is for controlling my Chromecast.</p>
<p>My Chromecast is for watching Netflix.</p>
<p>Netflix is for watching shows I already own on DVD but can't get because I'm holding a baby who doesn't want me to move a single, solitary inch.</p>
<p>Hammocks, however, I understand.</p>
The Upcoming iPhone 6: Everything we know so far!2014-06-25T00:00:00Zhttps://danielcwilson.com/blog/archives/52/<p>Nothing.</p>
Implications of an Open Sourced WinJS2014-04-02T00:00:00Zhttps://danielcwilson.com/blog/archives/47/<p>The big news (to me) out of Microsoft's Build conference was that Microsoft is <a href="https://github.com/winjs/winjs">open sourcing WinJS</a>. I think it is the impetus for the other big announcement about "universal apps" running all the way from phones to Xboxes.</p>
<p>WinJS was introduced a couple of years ago as a library to develop native Windows 8 apps using typical front-end web tools. I've talked about it here and there on my blog, and in further detail during my recent SXSW talk about developing responsively for Windows 8.</p>
<p>The main weak point of WinJS was that you could only use it on Windows 8 and 8.1. Not Windows Phone and not in the browser. Releasing on multiple platforms and prototyping functionality quickly in the browser were out of the question. This open sourcing, in theory, changes that. Now a single codebase should be able to work well across devices and even platforms.</p>
<h3 id="adaptive-input" tabindex="-1">Adaptive Input <a class="direct-link" href="https://danielcwilson.com/blog/archives/47/#adaptive-input" aria-hidden="true">#</a></h3>
<p>I make no secret that I am a web developer, not a Microsoft developer. The fact that they are reaching out to web developers is fantastic. Their vision for Windows across platforms is right in line with what I love about the web.</p>
<p>As a web developer, we can make no assumptions about how a person views our content. For a brief time it was common practice to assume "small screen" and "touch" were equivalent. Or that "mobile" meant "320px." We're smarter than that, and with Windows 8.1 plus these upcoming changes, Microsoft makes sure we assume nothing. Windows 8.1 already has great handling of touch, stylus, and mouse... abstracting out what can be and allowing for specific gestures when possible. Keeping an <a href="http://www.lukew.com/ff/entry.asp?1750">adaptive input approach</a> (as discussed by Jason Grigsby) in mind is key to a successful app across the myriad of devices available. Throwing speech and Kinect gestures to the forefront of Windows, too... well it admittedly makes it more difficult to develop yet, if done well, more satisfying for the user.</p>
<p>I feel like we are at a point where handling screen size is the easy part of successful web development. Making it look great everywhere is one thing. Making it work great everywhere is the challenge... and the fun.</p>
South By Reflections2014-03-21T00:00:00Zhttps://danielcwilson.com/blog/archives/44/
<p>
Even though I walked around SXSW the last four years picking up Gowalla shirts
and free tacos (breakfast and otherwise), 2014 was the first SXSW I went to as
an attendee. There are countless people bemoaning that it has lost its spark
(though I think most people are recycling their articles from last year... or
the year before... or the year before...). Not only did I attend, I also had
the pleasure to give my first presentation at a conference. Here are a few
observations and things I appreciated about SXSW.
</p>
<p>
The fact the organizers can maintain order across three full festivals and so
many smaller ones simultaneously amazes me. "Maintaining order" actually
undervalues it greatly because schedules are kept, sessions begin promptly,
and the various venues remain in sync. The volunteers and organizers deserve
an amazing amount of credit for that.
</p>
<p>
There was one hiccup during the prep for the first day of workshops where the
online sign up list was not working properly. But the organizers worked off
printouts and the delay was negligible.
</p>
<h3>Presenting at SXSW</h3>
<p>
Leading up to my session I was, to be honest, regretting submitting the talk.
The only comments I saw on Twitter about the session were snark filled...
unavoidable I suppose, especially when the word "Windows" gets tossed around.
And as someone who has thirty followers and does not get involved heavily on
Twitter, I'm not used to seeing the public negative thoughts of something I
put a lot of effort in to create. Ultimately this was just something that
caught me off guard a bit. In fact, this might be the one topic I encountered
not yet discussed on the excellent
<a href="http://ladiesintech.com/" data-external="">Ladies in Tech</a> podcast
about
<a href="http://ladiesintech.com/category/podcast/" data-external="">speaking at conferences</a>.
</p>
<p>
Still, the more I thought about it the more I thought my topic was so niche
that no one would come out. Lo and behold they did, and I even saw smiles and
nods. And nobody yelled at me when I stumbled at the end when looking at code
while realizing I was running out of time and unsure how to adjust. And nobody
threw their Surfaces at me when I admitted I was a web developer first,
Windows 8 developer second (or maybe third)... or when I almost certainly
mispronounced XAML as I explained I would not be talking about it because I
didn't know what it really was. I think being honest up front about my
perspective helped set the tone for the session so no one was surprised when I
only talked about JavaScript and not anything.NET. In summary, even if my talk
was more ramble than not (as it seemed to be in my head), I feel I had several
good points and the feedback has been invaluable. Thanks to everyone who came,
and thank you to others for the encouragement.
</p>
<h3>SXSW at Large</h3>
<p>
Yes. There is a lot of marketing to be found. That may or may not have been
the case ten years ago. To someone just walking around that might be all they
see. To someone who doesn't understand the session titles talking about some
really cool technology or idea that might be all they see. There are two main
points though about the marketing I noted: You can avoid it... and some of it
is done well.
</p>
<p>
First of all, just avoid it if you don't want to see it. Stay in the
convention center or the other venues and watch Neil deGrasse Tyson... or
check out
<a href="http://twitter.com/globalmoxie" data-external="">Josh Clark</a>'s
fantastic ideas on connecting devices through the web... or learn how
companies like <a href="http://seesparkbox.com/" data-external="">Sparkbox</a> are
using (the rather forgotten practice of) apprenticeships in the world of the
web. Or you can even stumble upon something that has nothing to do with your
day job or normal interests... like I did when I happened upon
<a href="http://travisswicegood.com/" data-external="">Travis Swicegood</a>'s talk
about how the
<a href="http://www.texastribune.org/" data-external="">Texas Tribune</a> is using
public data records to create their great visualizations and more. It might
seem hard to maneuver, but it's also really easy to know what to avoid when
you see a ton of signs and bright colors.
</p>
<p>
Secondly, not all marketing is bad. Sure, we're humans and being told how to
think is not our favorite. But what I appreciate is seeing large national
brands supporting and getting the name our of smaller local/Texas companies.
Nest served
<a href="http://www.goodpops.com/" data-external="">GoodPop</a> popsicles. Yahoo!
had Austin Amber from
<a href="http://www.independencebrewing.com/" data-external="">Independence Brewing</a>. AT&T (and I think eighteen other companies) had
<a href="http://www.chilantrobbq.com/" data-external="">Chi'lantro</a> tacos. How
great is that? Everybody is going to see them, and of all their options they
chose (I assume?) to go with local companies for their giveaways.
</p>
<h3>The Ultimate Takeaway</h3>
<p>
I had fun, learned a lot, missed a lot, and simply became too tired to really
enjoy any of the free shows for the Music festival. But that's okay as I
completed one of my goals for the year (present at a conference). It was a
great place to start that journey as well, with this festival that could have
easily outgrown itself years ago but continues to flourish as it grows bigger
and bigger.
</p>
Windows Store Development Resources2014-02-03T00:00:00Zhttps://danielcwilson.com/blog/archives/38/
<p>
I’ve lamented before how it is hard to find information about details of
developing for Windows 8. It’s great that we can use front end technologies to
build apps, but the fact that there are three languages to develop in divides
the available information.
</p>
<p>
I am leading a workshop session (<a href="http://schedule.sxsw.com/2014/events/event_IAP25597" data-external="">Taking the Responsive Web to Windows 8</a>) for SXSW 2014. While working on my slides and a sample project, I am trying
to find details that I’ve never seen or found once a long time ago without
remembering the source. Every once in a while I find the right search term
(Windows 8? Windows Store? WinJS? IE 11? The Non-XAML Way of Doing Something?)
and stumble upon something great.
</p>
<p>
I plan to write more about Windows over the coming months, and will try to
point to these great sources I find.
</p>
<p>
I knew I read somewhere that IE does not follow the “use 3D transforms to
trigger hardware accelerated transitions” model that Webkit has been using for
years. Before putting this in my talk I needed the source. After 4 hours of
searching, I found a great description of
<a href="http://msdn.microsoft.com/en-us/library/windows/apps/hh750312.aspx" data-external="">Performance with Windows Store apps</a>. Among other good information,
<a href="http://msdn.microsoft.com/en-us/library/windows/apps/hh849087.aspx" data-external="">animations are discussed</a>. In short, any transition on opacity or transforms (3D or 2D) will cause the
animation to run independently of the main UI thread.
</p>
<p>
The second resource I found today is one that I surely should have found
sooner.
<a href="http://dwcares.com/" data-external="">David Washington</a> discusses
seemingly-not-well-documented pieces of IE/WinJS/Windows like
<a href="http://dwcares.com/pull-to-refresh-2" data-external="">chained panning/zooming and snap points</a>. I’m just beginning to review these, but they look informative.
</p>
Path to Palindromes: Puzzles and the Web2014-01-20T00:00:00Zhttps://danielcwilson.com/blog/archives/34/
<div class="project-screens">
<img src="https://danielcwilson.com/img/palindromes.png" alt="Screenshots for Path to Palindromes on iOS and Android" />
</div>
<p>
Path to Palindromes debuted this past week on
<a href="https://itunes.apple.com/us/app/path-to-palindromes/id777602313" data-external="">iOS</a>
and
<a href="https://play.google.com/store/apps/details?id=com.danielcwilson.PathToPalindromes" data-external="">Android</a>... for free. This is my first attempt at developing a game, and it was
admittedly a lot of fun. I used to tell people I don't have games on my phone,
but really it's just that they are all in word/number puzzle form.
<a href="http://www.atebits.com/letterpress/" data-external="">Letterpress</a>
and <a href="http://www.spelltower.com/">SpellTower</a> are two of my
favorites, and both begin simply as a grid made up of letters.
</p>
<p>
The objective: Find as many palindromes as possible within a grid of numbers
before time runs out. A little math/vocabulary refresher... a palindrome is a
number (or word) that reads the same backward as forward, such as 989 or
358853 (or mom or racecar). Score by connecting any adjacent/diagonal numbers
to form a palindrome. The longer the palindrome the more points you get.
Simple... as far as rules go.
</p>
<h3>Technically Speaking</h3>
<p>
To create the game, I used some familiar (to me) tools:
<a href="http://cordova.io/">Cordova</a> for packaging the app for the AppStore
and Google Play, <a href="http://getlavaca.com/" data-external="">Lavaca</a> for
client side MVC, and
<a href="http://eightmedia.github.io/hammer.js/" data-external="">Hammer.js</a>
for gesture abstractions (because dragging is so much simpler with it,
especially since I am completing a version for Windows and Windows Phone which
use the much-preferred-by-me pointer events spec instead of touch events).
</p>
<p>
Running the app on the iPhone or iPad will have some iOS7-esque things...
namely transparencies, blurs, and layers. The app is one main screen with
three actionable items that when tapped load a new screen on top of the main
screen. Since I kept it simple with no left-to-right transitions, I was able
to blur the main screen while the selected "sub screen" is maximized. This
involves a transition on the scale and opacity of the selected screen while
simultaneously transitioning the main background to a blurred version.
</p>
<p>
While you can animate CSS filters, I assumed (yeah... I'll do a test someday)
that it's not great for performance (going from filter: blur(0) to filter:
blur(40px) for example). Therefore I used a variation of a technique on the
great
<a href="http://css-tricks.com/snippets/css/transparent-background-images/" data-external="">CSS Tricks</a>
using two stacked backgrounds (my main background and the blurred version of
it) with the help of opacity, transition, and ::after. Is it perfect? No. Do I
feel it's close enough since it only happens for .35 seconds as a new section
is coming in? Yes.
</p>
<p data-height="250" data-theme-id="0" data-slug-hash="DtmCJ" data-default-tab="result" class="codepen">
See the Pen
<a href="http://codepen.io/danwilson/pen/DtmCJ">Blur background</a> by
<a href="http://codepen.io/danwilson">@danwilson</a> on
<a href="http://codepen.io/">CodePen</a>.
</p>
<h3>Time to Develop and the Main Hangup</h3>
<p>
I had the idea for this game in August, and took a vacation day to see if I
could get it working in a day. I got very close: The basic mechanisms, style,
and tapping the board to select tiles worked (and this was before iOS 7
designs came into play)... but I got caught up on being able to simply drag
through the tiles to play. I wasn't using hammer for one, so I was tracking
everything myself. But there were two bigger pieces that tripped me up: How to
undo and how to make sure when you play diagonally with a finger that you
don't accidentally select nearby tiles.
</p>
<p>
So I stepped away and revisited it in December by scrapping everything and
starting over. This time I went in with Hammer so I didn't have to be
creative. Ultimately I went with a solution that puts an invisible element
inside each tile that is a circle, so the selection will not trigger until the
finger is over that smaller circle.
</p>
<div style="
position: relative;
width: 10rem;
height: 10rem;
margin-bottom: 1rem;
line-height: 10rem;
font-size: 2rem;
text-align: center;
border: 1px solid #333;
">
7<i style="
position: absolute;
background: transparent;
top: 27%;
right: 27%;
bottom: 27%;
left: 27%;
border-radius: 5rem;
background-color: rgba(40, 110, 180, 0.35);
"></i>
</div>
<p>
The rules then became if you are in "dragging mode" and your finger is over
the selectable circle, follow these rules:
</p>
<ul>
<li>
Is the current tile adjacent or diagonal to the last played tile? Then add
it to the current palindrome
</li>
<li>
If not, then is it the second-to-last tile in the palindrome? Then take away
the last tile in the palindrome (Undo action)
</li>
<li>Otherwise the tile is not actionable</li>
</ul>
<p>
Once this got a clear answer the game only a couple days of development. I
kept the game simple for a reason. Thanks to Cordova plugins that installed
without issue (Lee Crossley's
<a href="https://github.com/leecrossley/cordova-plugin-game-center/" data-external="">iOS GameCenter Plugin</a>
especially) and great support for the web on iOS7 and Android KitKat, I was
able to submit both to the AppStore and Google Play after a couple more days
testing.
</p>
<h3>The Web for Games</h3>
<p>
In my head, the web always seemed like it would be perfect for little puzzle
games, and this experiment proved me right, thankfully. If you want to play
online, I am also making the
<a href="http://adeptmentalmath.com/palindromes/play">game available in the browser</a>, since I talk about liking the web so much. Admittedly, I've not tested it
much in older browsers, but I'm releasing it more as a testing exercise...
which is why I waited so long to mention it.
</p>
<p>
Five years ago, I feel something like this wouldn't have made sense with
front-end web technology. But with a solid Javascript architecture, CSS
animations and transitions, and people thinking about how to support multiple
inputs like mouse and touch, it's now possible to develop well-performing
games in the browser.
</p>
<p>
If you have any feedback on the game, or if you want to share other examples
of browser puzzle games, reach out to me on
<a href="http://twitter.com/dancwilson" data-external="">Twitter</a>. I hope you
like it.
</p>
Other Browsers, Keyboards, and Height2013-11-14T00:00:00Zhttps://danielcwilson.com/blog/archives/20/
<p>
As a followup to my article on
<a href="https://danielcwilson.com/blog/archives/18">iOS 7's keyboard and height problems</a>, I
thought I'd check in with other browsers... and I was left more confused than
before. I am using the same <a href="https://danielcwilson.com/demos/ios7keyboard/">demo page</a> as my
last article for these other browsers with an element positioned absolute at
the bottom. I always thought I knew how this worked, but I was very wrong (or
everyone has changed how this worked, and I missed the conversion day). I
still need to test what has the potential to be the strangest of all... the
stock Android browser (the "IE 6" one).
</p>
<p>(Updated November 19, 2013: Screenshots added)</p>
<h3>Windows 8 IE 11</h3>
<p>
The keyboard here appears above the fixed content (as I would hope), and the
window and document heights appear unchanged (as I also would hope). I like
it.
</p>
<p>
<a href="https://danielcwilson.com/img/posts/20/Screenshot-8.png"><img src="https://danielcwilson.com/img/posts/20/Screenshot-8-300x168.png" alt="Windows 8 IE 11 with Keyboard Up" width="300" height="168" class="size-medium wp-image-30" /></a>
</p>
<h3>Windows Phone 8 IE 10</h3>
<p>
Visually, this actually behaves similarly to Windows 8's browser. The
document's height stays the same, so the keyboard is on a layer above the
footer, as I would expect. It differs from Windows 8, however, in that the
window height does actually change. So with the keyboard up, the window height
will be effectively the document height less the keyboard's height.
</p>
<p>
<a href="https://danielcwilson.com/img/posts/20/wp_ss_20131113_0004.jpg"><img src="https://danielcwilson.com/img/posts/20/wp_ss_20131113_0004-180x300.jpg" alt="Windows Phone 8 IE 10 with Keyboard Up" width="180" height="300" class="alignnone size-medium wp-image-31" /></a>
</p>
<h3>Android Chrome (4.3)</h3>
<p>
I was surprised to see behavior that more closely matches the busted iOS 7
WebView: The fixed footer stays attached to the top of the keyboard. As far as
heights are concerned - the document height here is the one that shrinks while
the window's stays the same. This is the opposite of the Windows Phone test,
and in my head makes less sense.
</p>
<p>
I will need to rerun this test now that upcoming versions of
<a href="http://www.mobilexweb.com/blog/home-screen-web-apps-android-chrome-31" data-external="">Chrome will allow homescreen apps</a>, similar to iOS. It should also be noted that the latest Android Firefox
(25.0) also pushes up the footer with the keyboard.
</p>
<h3>iOS Chrome & iOS Twitter App's Browser</h3>
<p>
Unsurprisingly (when you know that both Chrome and Twitter - and Facebook,
Flipboard, etc. - just use a WebView with some different controls than
Safari), both of these behave exactly as the busted WebView.
</p>
<p>
<a href="https://danielcwilson.com/img/posts/20/photo-2.png"><img src="https://danielcwilson.com/img/posts/20/photo-2-169x300.png" alt="Chrome test on launch" width="169" height="300" class="alignnone size-medium wp-image-26" /></a>
<a href="https://danielcwilson.com/img/posts/20/photo-1.png"><img src="https://danielcwilson.com/img/posts/20/photo-1-169x300.png" alt="Chrome + WebView Issues with Keyboard Up" width="169" height="300" class="size-medium wp-image-25" /></a><a href="https://danielcwilson.com/img/posts/20/photo-4.png"><img src="https://danielcwilson.com/img/posts/20/photo-4-300x169.png" alt="Fun with WebViews and Landscapes" width="260" class="size-medium wp-image-28" /></a>
</p>
<p>
I've always hated in-app browsers because they have always been just a poor
man's version of the actual Safari browser. Still... they remain in heavy use
since they are embedded in some very popular apps (as
<a href="http://www.lukew.com/ff/entry.asp?1801" data-external="">noted by Luke Wroblewski</a>) and some people falsely believe that iOS Chrome uses its own Chrome-like
rendering engine. With iOS 7 these limited browsers become much poorer.
</p>
iOS 7, Keyboards, and Height: A Lesson in Confusion2013-10-10T14:21:23Zhttps://danielcwilson.com/blog/archives/18/
<p>
It might be a bug, or it might be an intended change… but the keyboard affects
iOS web views in new ways with iOS 7.
</p>
<p>
Taking a look at three different ways to view a web page, we see different
behaviors for the height of the document:
</p>
<ol>
<li>
<strong>In a fullscreen/homescreen web app:</strong> The height on an iPhone
5s of the app is 548px (20 less than the screen's height, to account for the
status bar). When a keyboard opens, the height changes to 288px (or the
screen height less the 20px for the status bar and less the height of the
keyboard. On iOS 6 and earlier, regardless of the keyboards presence the
height was 548px.
</li>
<li>
<strong>In a WebView inside another app:</strong> Similar behavior to the
fullscreen app. Whatever the height of the WebView is what is returned for
the document height. When the keyboard appears it shrinks the height to the
remaining screen real estate left by the keyboard. Again, this was not the
case in earlier iOS versions.
</li>
<li>
<strong>In plain, ol' Safari:</strong> The height does not change when the
keyboard appears. It appears on top of the web view and does not affect the
document. Just like we always remembered.
</li>
</ol>
<h3>Why is this relevant?</h3>
<p>
Check out this <a href="https://danielcwilson.com/demos/ios7keyboard">iOS 7 keyboard issue demo</a> in
both iOS 7 Safari and as a fullscreen app saved to the home screen. You can,
of course, also check it out in other browsers where a keyboard comes up on
the screen including earlier iOS versions.
</p>
<p>
Obvious cases are elements that are positioned absolute or fixed at the bottom
(shown on the demo page). They will float up with the keyboard and potentially
cover up the focused input. This is all the more likely to be annoying on a
3.5-inch screen (or… change to landscape). The demo page will act a little
buggy if you try this in landscape because if you tap the text field, the
keyboard will come up and the footer will cover up the field. The focus event
is never actually triggered, but the keyboard is up and there is a cursor in
the covered field… though you likely will not be able to type in it.
</p>
<p>
Use of flexbox can also create similar unintended scenarios. Additionally,
people are also seeing the
<a href="http://trentwalton.com/2012/01/11/vertical-media-queries-wide-sites/" data-external="">power of min/max-height</a>. Depending on what changes in the media query, this issue could cause
jarring results to the user.
</p>
<h3>Next Steps</h3>
<p>
So... I'm not sure where we go from here. I've not found much discussion of
this (hence my write-up). If you have thoughts or find new information, let me
know on twitter (<a href="http://www.twitter.com/dancwilson" data-external="">@dancwilson</a>). I'll follow up with anything I find.
</p>
Taking the Responsive Web to Windows 8... and 8.12013-10-10T07:33:10Zhttps://danielcwilson.com/blog/archives/17/<p>I've worked on three Windows 8 apps using HTML/CSS/JavaScript (one largescale for a client and <a href="https://danielcwilson.com/projects">two smaller apps</a> of my own), and I started all of them before Windows 8 was officially released. Going into the projects one of my favorite features was the multitasking views, showing two apps side by side. It seemed ripe for responsive web design...</p>
<p>We made mistakes.</p>
<p>Microsoft had a key recommendation early on to support these multiple "view state" scenarios: Take a more "adaptive" approach where you target the four view states specifically using media queries with four specific -ms-view-state values (fullscreen-landscape, fullscreen-portrait, filled, snapped). Snapped view was always 320px wide. Filled was always the device width minus 320px. Portrait was always fullscreen. Landscape was also fullscreen horizontally. While we all felt (on the client project) that a more responsive approach was better and future friendly, based on Microsoft's recommendation + an aggressive timeline + little documentation and community to find support at the time we decided to take this differing approach.</p>
<h3 id="enter-windows-8.1" tabindex="-1">Enter Windows 8.1 <a class="direct-link" href="https://danielcwilson.com/blog/archives/17/#enter-windows-8.1" aria-hidden="true">#</a></h3>
<p>This favorite side-by-side approach for apps in Windows 8 received an important advancement in Windows 8.1, one that fits in much better with 2013. Snapped view is no longer a guaranteed 320px. When you launch apps side by side they are by default each 50% width. Launch another and they fit into thirds. Want to make one slightly bigger? drag it and it is done. The world of four fixed states is gone, and an app can fit any number of widths and heights. Great for the user? Definitely. Great for the developer stuck in self-described 2010-fixed-width glory? Not at all. Great for developers excited about the real world where devices range from tiny to huge, and everything between and beyond? Yes.</p>
<p>And is it great for developers like me who followed the Windows 8 recommendation? Sure, because it reminds me to listen to myself and do things right the first time. Windows 8 was a big unknown in the summer of 2012. We knew you could develop with web technologies, and there was a WinJS library. Beyond that we didn't know if coding it like a typical single-page website was appropriate. There was the thinking that beyond using JavaScript, we needed to rethink how we worked. This turned out to be again a lesson in overthinking. If you can use HTML/CSS/JavaScript... then use it in the way that makes sense. We followed the recommendation that ultimately was not in line with our current thinking, and now we get to revisit everything and rework it. We could have coded everything without using the four view states and had it work the same in Windows 8 and been prepared for the change that eventually came in Windows 8.1. Alas.</p>
<h3 id="specific-changes-in-windows-8.1" tabindex="-1">Specific Changes in Windows 8.1 <a class="direct-link" href="https://danielcwilson.com/blog/archives/17/#specific-changes-in-windows-8.1" aria-hidden="true">#</a></h3>
<p>Most of these changes are highlighted in <a href="http://msdn.microsoft.com/en-us/library/windows/apps/dn263112.aspx">Microsoft's documentation</a>.</p>
<p>First of all, <strong>the four specific view states in media queries are deprecated</strong>. Snap view even has a new minimum width of 500px (though you are able in your app's manifest to change it to 320px if desired). So they will continue to work today, but may not work in the way you expect if you target your app to the 8.1 SDK. Instead, use the more common media queries for min- and max-width (and the same for height).</p>
<p>Similarly, <strong>the ApplicationView.value property in JavaScript is deprecated</strong>. So instead of checking against this property to see which view state you were in, you directly fetch the document.documentElement.offsetWidth. <a href="http://msdn.microsoft.com/en-us/library/windows/apps/hh770584.aspx">PageControls</a> in Windows 8 had an updateLayout method that would be called as a view state changed. I've not been able to find a mention of this being deprecated, but it appears the new suggested approach is simply to add a listener for the window's resize event.</p>
<p><strong>There is no more unsnapping</strong>. Well... at least it, too, has been deprecated. We used this one a few times in our client app. Click on an item while in snap view and the app will, as expected, try to make your app be the on in the filled state, and shrink the other to snap view. It worked well, but Microsoft clearly wants your app to work regardless the width/height to which it is constrained. Reasonable.</p>
<h3 id="our-new-approach" tabindex="-1">Our New Approach <a class="direct-link" href="https://danielcwilson.com/blog/archives/17/#our-new-approach" aria-hidden="true">#</a></h3>
<p>Do it right. Use relational units. Minimize our use of WinJS-y methods when there is a standard web alternative (unless there is a performance gain, etc.).</p>
<p>Also, with the old four view states, the thinking was often keep portrait, landscape, and filled relatively the same (scrolling horizontally as all good Windows 8 apps should), but make the snap view flow vertically (as the best Windows 8 apps did). With the increased minimum width, the vertical flow does not make as much sense always. So we are experimenting with always scrolling horizontally, adjusting list styles/sizes, and placement of flyouts, etc. Only time (and users) will tell what approach makes the most sense on this new platform.</p>
<p>The one thing we know for sure is that this approach for Windows 8.1 is a welcome change (even if we have to rework based on the original Windows 8 implementation/recommendation). It's a step in the right direction.</p>
Succeeding (with a Caveat) with Lavaca, Cordova 3.0, and BreweryDB2013-10-07T00:00:00Zhttps://danielcwilson.com/blog/archives/16/<p>I've said it before, and I'll say it again - JavaScript MVC Frameworks are not my thing... typically. MVC is logical to me, but doing so much on the client-side often leads developers to only support a limited set of browsers/devices. Hesitations aside, I've found places where I feel MVC frameworks can shine. Only want to support hybrid apps where you take a native app and package web views in some fashion? You already are limiting the browsers and devices, so this can work. I won't go into the business decision to go down this route in the first place - but assuming this is your requirement, then a JavaScript MVC can be a great way to go.</p>
<p>All this to say - I've created an app called <a href="https://itunes.apple.com/us/app/local-on-tap/id687592298?mt=8">Local on Tap</a> to experiment more with the <a href="http://getlavaca.com/">MVC framework Lavaca</a>, the latest release of <a href="http://cordova.io/">Cordova</a>, and a crowdsourced database for craft brewing called <a href="http://brewerydb.com/">BreweryDB</a>. I released it to the iOS App Store a month and a half ago, with the Android version coming soon (after a little more real device testing).</p>
<h3 id="lavaca" tabindex="-1">Lavaca <a class="direct-link" href="https://danielcwilson.com/blog/archives/16/#lavaca" aria-hidden="true">#</a></h3>
<p>Lavaca has come a long way since its first version a year ago. If you've got Node installed, setup is quick, and the integration with Cordova is nice (although it was a lot more useful before Cordova 3.0's changes). Pull down a <a href="https://github.com/mutualmobile/lavaca-starter">starter project</a>, npm install, run "grunt server"... and you've got an app running on a local server. Run "grunt build" and you have a minified codebase ready to deploy to a server.</p>
<p>Lavaca has several recommendations stated out of the box with the starter app, but I chose to go a different route in many regards. There is a HeaderView that acts globally and based on Model changes will change the title and potentially determine whether back buttons should show, etc. I chose to keep the headers inside each View. This gives more flexibility in my mind, and also works more nicely with iOS 7 where headers and the status bar are tied together... and more closely tied to each individual view.</p>
<p>As far as working with it, it follows a fairly typical MVC pattern. You define Controllers that route to different Views with different Models, all while maintaining state, history, etc. The key to a successful Lavaca project might be in proper usage of the View's redraw method. To keep the app feeling snappy, as you click on links, I direct the user immediately to the next screen... even though the content for that screen is usually unknown and being fetched by an API call. After the new screen has completed its "enter" event and the API has returned with the appropriate data, the screen (or typically, just a section of the screen) is redrawn with the new content. Too much of this (or while animations and other events are occurring) and there can be flashes and a stuttering feel. Keeping it after "enter" and only doing the redraw once keeps things feeling responsive.</p>
<h3 id="cordova-3.0" tabindex="-1">Cordova 3.0 <a class="direct-link" href="https://danielcwilson.com/blog/archives/16/#cordova-3.0" aria-hidden="true">#</a></h3>
<p>I'm a visual guy, and command line has never been my friend. College professors swore that even when coding in object oriented languages, vi was the only true text editor. I never bought into it, but I'm starting to understand the benefits of command line tools. Adding a plugin is easy (if you know the git URL) and building a project is easy. Lavaca used to do a lot of this for us, but now Cordova does it on its own, and it's a welcome change. I've not yet experimented much with the merges folder, but it seems like a useful way to get around anything that requires it. Though, hopefully nothing does.</p>
<h3 id="brewerydb" tabindex="-1">BreweryDB <a class="direct-link" href="https://danielcwilson.com/blog/archives/16/#brewerydb" aria-hidden="true">#</a></h3>
<p>I love the idea behind this service... and its reliability. They support the little known breweries, and since data is often populated by the fans of these breweries, it often is quick - even shortly after a tweet goes out about a new offering. The API is easy to work with and gives a solid amount of information. It is one of the best documented and well organized APIs I have worked with in a while.</p>
<p>I wanted to do this project quick and without a server component (to play with Lavaca), and since the BreweryDB service does not support CORS, packaging the app with Cordova seemed like a solid way to go. This, as stated at the beginning, means my requirement was for a limited set of devices.</p>
<h3 id="thoughts" tabindex="-1">Thoughts <a class="direct-link" href="https://danielcwilson.com/blog/archives/16/#thoughts" aria-hidden="true">#</a></h3>
<p>After working through this project, I feel this lack of broad support is my only hesitation to do this more often. I'm a web developer, and any time I only see something work on an Apple device or something that supports touch I wonder why bother with the web. The web should be for everyone... and it's not hard to support them all. But you have to choose the right tools. And build the right way. And progressively enhance properly. And love the world.</p>
Using Lavaca to Start a New Mobile App: Part 12013-08-14T00:00:00Zhttps://danielcwilson.com/blog/archives/14/<p>
It goes without saying, so I’m going to say it - there are a lot of frameworks
out there to handle front end (JavaScript) MVC. For every
<a href="http://backbonejs.org/" data-external="">Backbone</a> there is an
<a href="http://angularjs.org/" data-external="">Angular</a> or
<a href="http://emberjs.com/" data-external="">Ember</a>... but my current go-to
is the relatively new <a href="http://getlavaca.com/" data-external="">Lavaca</a>.
I aim to show you how to get your own Lavaca project up and running (I'll be
basing this from Lavaca 2.1), but let’s start with some basic reasons why I
currently use Lavaca over other options.
</p>
<ul>
<li>
Great Integration with Cordova/PhoneGap: I only consider using JavaScript at
an architecture level on the front end when I can guarantee it is present.
This is not the case in a web browser, so I usually am packaging up my code
as a hybrid app for mobile.
</li>
<li>
Use of Promises: Once I understood the Promise concept and broke out of
passing callbacks, I never wanted to go back. Check out
<a href="http://getlavaca.com/#/guide/Promises-Pattern" data-external="">Lavaca's introduction to Promises</a>
</li>
<li>
Built for Mobile First: Ever since “Mobile first” was first muttered it
clicked with me, and now drives how I approach every project. It’s a
continuation of the mindset of progressive enhancement.
</li>
</ul>
<h4>Starting a Project</h4>
<p>
There are a few prerequisites, but if you have dabbled with another MVC
library or Node, then you likely will already have everything you need.
</p>
<p>
You’ll want the latest stable version of
<a href="http://www.joyent.com/blog/installing-node-and-npm" data-external="">Node and NPM</a>. Oh, and a Mac.
</p>
<p>Then it’s a matter of grabbing the Lavaca CLI tool in a Terminal window</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">curl</span><br />https://raw.github.com/mutualmobile/lavaca/master/getlavaca <span class="token operator">></span><br />/usr/local/bin/getlavaca <span class="token operator">&&</span> <span class="token function">chmod</span> +x /usr/local/bin/getlavaca<span class="token operator"><</span></code></pre>
<p>Once everything is installed...</p>
<ol>
<li>
In the Terminal, go to the directory where you want your project and run: <pre class="language-bash"><code class="language-bash">getlavaca</code></pre>
</li>
<li>Use the master branch unless you can find a reason not to</li>
<li>Name your main app directory</li>
<li>
Go to your newly created app’s directory <pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span><br /> directory-name</code></pre>
</li>
<li>
Install Lavaca’s Node dependencies <pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span></code></pre>
</li>
<li>
Start a server via grunt <pre class="language-bash"><code class="language-bash">grunt server</code></pre>
</li>
<li>
In a browser go to
<a href="http://localhost:8080/" data-external="">http://localhost:8080</a>
</li>
</ol>
<p>You now have an example project running!</p>
<p>
But we don’t want to just run in a browser... we want to build this as a
hybrid application. Lavaca doesn’t assume anything at creation, so we need to
tell Lavaca we want to build for specific platforms with Cordova.
</p>
<p>
This consists of installing the Cordova CLI and then initializing a fresh
iOS/Android/etc. project as needed. Running the below commands by default will
create a blank iOS project and a blank Android project. Read the
<a href="http://getlavaca.com/" data-external="">Lavaca Guide</a> to find out how
to change that.
</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> -g cordova grunt cordovaInit</code></pre>
<p>
This will sync Lavaca’s commands with the Cordova CLI and create source
folders for both projects. The last command needed is
</p>
<pre class="language-bash"><code class="language-bash">grunt build</code></pre>
<p>
This will merge your HTML/CSS/JS with the Android and iOS src projects, by
creating a new folder in your app’s directory called build. If dealing with an
iOS project, for example, open build/ios/AppName.xcodeproj ... hit run... and
you’ll see your app as packaged by Cordova. Part 1 is now complete.
</p>
<p>
Part 2 will review the basic structure of an app, and what it takes to replace
the example app with your own.
</p>
The Little (&) Barely Documented) Things in WinJS & IE - Handling Basic Input2013-07-31T00:00:00Zhttps://danielcwilson.com/blog/archives/12/<p>When I first started working with Windows 8 in August 2012 (a couple of months before Windows 8 released), I was excited to start writing native apps with my beloved web technologies. I didn't know what was really required other than Microsoft had some library called WinJS and a very much improved version of Internet Explorer. So I opened up my browser and started looking at documentation.</p>
<p>Only... this was next to impossible. There were a couple basic "Quickstart" tutorials and some bits of documentation, but finding information on these ListViews, Flyouts, and semantic zoom interactions was hard. Fortunately, a lot has changed in a year, and it's now a lot easier to find information about how WinJS handles something or what Internet Explorer 10 needs for a given CSS rule. Yet some concepts remain largely hidden or misunderstood. For my future reference as much as anything else, here I'm posting a series with some useful bits to remember when developing Windows 8 apps (which will translate to the browser as well since nothing below is specific to WinJS). This inaugural post focuses on the basics of handling input.</p>
<h3 id="pointer-events-not-touch-targets" tabindex="-1">Pointer Events, not Touch Targets <a class="direct-link" href="https://danielcwilson.com/blog/archives/12/#pointer-events-not-touch-targets" aria-hidden="true">#</a></h3>
<p>Apple and WebKit got developers used to handling event touches (or targetTouches/changedTouches) on touchstart, touchmove, and touchend events. Microsoft does not support this, and instead implemented what is now a <a href="http://blogs.msdn.com/b/ie/archive/2013/05/09/w3c-transitions-pointer-events-to-candidate-recommendation.aspx">W3C Candidate Recommendation</a> - Pointer Events. There are similarities to the WebKit way - there are pointerdown, pointermove, and pointerup events, for example. But Pointer Events take a different approach in that they support all types of pointer input.</p>
<p>Mouse, touch, stylus - these are all covered by one event. There's no more worrying about handling touch one way and mouse another (and then worrying about if you properly disabled the corresponding mouse event when touch was used instead). If you need to distinguish, there is a pointer type inside the event to delegate different action paths.</p>
<p>I plan to write another post in detail about Pointer Events, but until then here are key articles to learn more.</p>
<ul>
<li><a href="http://msdn.microsoft.com/en-us/library/ie/hh673557.aspx">MSDN: Introduction to Pointer and Gesture Events</a></li>
<li><a href="http://msdn.microsoft.com/en-us/library/ie/dn304886.aspx">MSDN: Pointer Events Updates (for the upcoming IE 11)</a></li>
<li><a href="http://msdn.microsoft.com/en-us/library/ie/hh772103.aspx">MSDN: MSPointerEvent Object</a></li>
</ul>
<h3 id="css:-ms-touch-action" tabindex="-1">CSS: -ms-touch-action <a class="direct-link" href="https://danielcwilson.com/blog/archives/12/#css:-ms-touch-action" aria-hidden="true">#</a></h3>
<p>More so than mouse and stylus input, touch has several default gestures that perform actions. Scrolling/panning, zoooming, and other actions are defined by the OS. So if you have a block of content that has overflow scroll, when you move your finger in that block, the content will pan. We expect this as a user. But as a developer, there are cases where we want to turn off the expected behavior and handle it on our own with JavaScript.</p>
<p>This is where the CSS property -ms-touch-action comes in.</p>
<p>Well, almost. First... an anecdote.</p>
<p>Our client for my first Windows 8 project wanted to turn our Semantically Zoomable ListView on the initial screen of the app to behave like the Windows 8 Start Screen. Seemed reasonable. Windows provided a ListView that looked like the tiles of the Start Screen. From there we just needed to add the abilities to toggle visibility and drag/reorder. Here's where we hit several walls. We finally found the early documentation of Pointer Events (not as thorough as it is now), but as our many unhit breakpoints made clear, our pointer event listeners were not triggering.</p>
<p>Finally we caught wind of a -ms-touch-action, which has a default value of auto. It sometimes seems backwards how this works, at least as it was originally presented. But once you understand the intent it becomes a lot clearer.</p>
<p>The default value of auto means if a user performs a standard OS gesture, do what the OS wants to do and do not fire Pointer Events. You can also specify none or one (or more) of the following values:<br />
pan-x pan-y pinch-zoom manipulation double-tap-zoom (added for IE 11: cross-slide-x cross-slide-y)</p>
<p>Saying "none" will mean nothing will happen by default, but Pointer Events will be triggered for all touch interactions. Otherwise if you specify a specific value, only the specific value will be taken care of by the OS defined action (still with no Pointer events fired) while other gestures will fire the Pointer events. So if you specify only pan-x, then horizontal scrolling will work by default while dragging on the screen vertically will perform no action by default but will fire Pointer events.</p>
<p>For a larger example, back to the anecdote of recreating the feel of the Start Screen, we wanted to handle drag/reorder but still allow horizontal panning, as the Start Screen does. Specifically with touch on the Start Screen, if you want to move a tile, you must perform what Microsoft calls a "CrossSlide" gesture. This is essentially dragging a tile vertically until it "snaps" out of place and can then be moved freely (as a sidenote, this gesture does a lot more and can be implemented in other ways, but this is sufficient for the purpose of reordering). So we had to set -ms-touch-action as pan-x, and then we set up pointer event listeners to handle movement in the vertical direction.</p>
<p>The CrossSlide is an interesting beast (and IE 11 makes it a lot easier to deal with), and I plan to discuss it more, along with lessons I've learned from it in regards to WinJS development.</p>
<h3 id="more-to-come" tabindex="-1">More to Come <a class="direct-link" href="https://danielcwilson.com/blog/archives/12/#more-to-come" aria-hidden="true">#</a></h3>
<p>There's obviously a lot more to be said about Pointer Events and gestures. I plan to get more into detail, especially breaking down the CrossSlide with examples (which will lean heavily on another barely documented item in WinJS... Gesture Recognizer).</p>
Missed Opportunities... On Repeat!2013-07-06T00:00:00Zhttps://danielcwilson.com/blog/archives/8/<p>I'm content, but I'm not fully excited about my work.</p>
<p>I've got a website and online presence, but it's not representative of my latest skills.</p>
<p>I've got a resume, but it's not ready to send when needed.</p>
<p>I've got things to say, but I don't find the places to say them.</p>
<p>These are all thoughts I've had in the past, and they are all thoughts that come back time and time again. At first glance they don't seem that important. At least there's something there for each... but they never really meet the potential. And ultimately the fact that each is often true at a given point means I miss opportunities. A dream job that opens up. A conference asking for proposals. I feel as though I'm always at a point where I am perfect for something that comes by, but I've not made that known to anyone but me. Which does not help me. By the time I have time to update my resume or type up a proposal the opportunity is gone.</p>
<p>I've been trying to find a way to break out from these missed opportunities and be ready the second something comes up. I have no idea if it will work, but at least I am committing to something and we will see what happens. Here's my current plan.</p>
<ul>
<li>Commit one evening at the first of each month to make sure my resume is representative of my experience.</li>
<li>Commit one evening at the first of each month to make sure my website looks fresh... either by design or content. Make sure my latest work is on there somehow.</li>
<li>Commit at least one evening each month to work on open source projects. My Github account looks pretty dry right now, even though I've worked on a few projects that I need to release there and can contribute to others.</li>
<li>Release my work regularly. This one's not clearly defined... but I (as I think is often the case) have a problem calling code/design/etc. finished... there's always something more I can do to make it better. But I need to iterate and release more often for my side projects, and for my blog, and for my other contributions.</li>
<li>Similarly, release work that is small but visible. What I mean here is that I have done a great amount of work at my office that I'm really proud of... Progressive Enhancement, Responsive design, Mobile First... working on the latest iPhone all the way back to a Razr. But it was for a client that used it for internal projects. No one will ever see it outside of that company. So I need to take what I learn and use them in other places. Small little websites. Small Windows 8 apps. Small Cordova apps. Small JavaScript libraries. Just to get that knowledge out there.</li>
</ul>
<p>These are things that really don't take much time, but the longer I wait between them the longer they take. Just like cleaning a shower.</p>
A new place and the same old issues2012-01-10T00:00:00Zhttps://danielcwilson.com/blog/archives/6/<p>I started my first new job in almost five years recently. With it came a change from working with a single organization to the world of client services. Mobile services to be precise.</p>
<p>I'm on the newest team there - the Web Developers. It is always funny to me that the Web Developers are the new kids on the block in mobile (according to the majority of people with whom I interact). With the company telling us we have to agree and choose a framework such as Sencha Touch (since these directions are coming from people in the native world, not the open, progressively enhanced web world I like to frequent), there are many conversations that have taken place where tempers have flared a bit with different members. But something else has been bugging me much more, and it has occurred ever since I first learned HTML and took my first computer science class in college. People are ashamed of their code.</p>
<p>Since I started, I've heard multiple people tell me to forgive their code because it's not that great. If only I had had a different requirement I would have supported that browser earlier. I always told myself I would stand by my code, but when I heard myself make an excuse to my coworker for my Javascript ("Full disclosure: I've never worked with JQuery Mobile before, and that's what the original developer I took over for started with, so I think I completely butchered the MVC pattern that was trying to be achieved") I realized something was wrong, and it bothered me greatly.</p>
<p>It might just be the organizations I have worked with, but I have always heard more people make excuses or claim they just wrote the worst code of the their ("but at least it works!") than those who are proud of their work. Why do we do it?</p>
<p>I hate feeling embarrassed to show my code to other people. But it happens. My first code review in the career world was horrible. I was proud of what I wrote, but then another developer was told to find at least five things to improve. Whether or not there was anything to really improve. So arbitrary best practices were thrown at me, and my non-technical boss looked at the review with disappointment in my skill. Beyond that, we would have demo days where we would share code with each other that we were proud of, and people would start interrupting ("you should have used a static final synchronized class instead of a static final class!").</p>
<p>From college and beyond, I've studied/worked with people who will look at legacy code and openly mock it - even if it's really not that bad. It's not in their preferred style so it must suck. Everyone does it. But so many times, the person who worked on the code is there. Maybe they worked on it five years earlier when they were a junior developer, forgive them. Maybe they were in a time crunch and management was pushing the timeline first, forget it. Maybe it's better than what you would have done, so be quiet.</p>
<p>So I wonder if that's it. There are a lot of great developers out there who write great code. There are a lot more out there who write great code but who might have missed some optimization here or there. We should all be proud of what we do - <em>especially</em> if it works. There's always room for improvement - for everyone. Especially in this day and age. The iPhone has only been out for less than half a decade. Mobile computing is still young. Heck, the web is still young. What was great a great coding technique last year may be irrelevant the next. I take pride in seeing things work, and seeing users interact with my work. Even if I declare one Javascript variable in the middle of a method. Or if my previous life as a Java developer makes me mess up my terminology for Javascript functions.</p>
A new site and a new blog2011-06-04T00:00:00Zhttps://danielcwilson.com/blog/archives/3/<p>Here we are with the first blog post on my new Wordpress setup on my recently updated site.</p>
<p>I've been doing a lot of reading on web design and mobile design over the last three years, but my job has kept me busy enough to not allow me to put all that I've learned into practice. I've certainly been able to put some things into play, but it's hard working for a large organization that views the web and mobile offerings as secondary. We were finally approved to begin work on a mobile web offering (we've had a website and iPhone/Android apps for some time now) three years after it was proposed and prototyped. And that's certainly fine, I understand approvals take time. It does amaze me though how people still do not understand why we would want to create a mobile web app.</p>
<p>As a background, I work at a financial institution, and we are talking specifically about online banking. Transferring funds, viewing account details, opening accounts... you name it and we have it. We were even one of the first to use remote deposits from your computer (Scanning a check to deposit it), as well as on iPhones, Androids, and even the iPad 2 with their cameras and our apps. Our website has been converted over the last few years to use a lot of web standards and progressive enhancement to work across most browsers and screens. But it's still a pain to use on mobile devices. And because our business unit has talked to mobile app consulting firms, the belief is that we only need to focus on iPhone and Android through apps. Yet, literally everyday we get questions about why there's no way for Blackberry users to access our full site. Less often, but often enough we get requests for Windows Phone 7 and webOS users. We even get questions from our iPhone and Android users asking the same thing, as even though we have apps for them they 1) don't know about it or 2) simply would rather use the browser.</p>
<p>There's a place for native apps, and I'm glad we have them, but it's only a part of the puzzle and we are missing out by not having a web version that is more usable for these smaller screens and different input features. It's not one or the other when it comes to apps - both have a place and purpose.</p>
<p>Regardless, here's my small site redesign that adapts with responsive web design and finally gets my thoughts out here with this blog. It's been a long time coming, but Spring is in the air with Summer to soon follow, so I shall make the most of it.</p>