Tobias Ahlin Words by Tobias Ahlin http://tobiasahlin.com Animating Link Underlines <style> .underlined-example { position: relative; color: #fff; text-decoration: none; font-size: 24px; margin-bottom: 15px; display:inline-block; } .underlined-example:hover { color: #fff; } .underlined-example:before { content: ""; position: absolute; width: 100%; height: 2px; bottom: 0; left: 0; background-color: #fff; visibility: hidden; -webkit-transition: all 0.3s ease-in-out 0s; -moz-transition: all 0.3s ease-in-out 0s; -o-transition: all 0.3s ease-in-out 0s; transition: all 0.3s ease-in-out 0s; -webkit-transform: scaleX(0); -moz-transform: scaleX(0); -o-transform: scaleX(0); transform: scaleX(0); } .underlined-example:hover:before { visibility: visible; -webkit-transform: scaleX(1); -moz-transform: scaleX(1); -o-transform: scaleX(1); transform: scaleX(1); } </style> <div class="size-960 banner-red"> <a href="http://tobiasahlin.com/blog/" class="underlined-example">Hover this link</a> </div> <p>I recently added a simple visual effect to this blog that I quickly fell in love with: when you hover blog headers, the link&#39;s underline is revealed by animating it out from the center. You can try it in the banner above.</p> <p>Creating this effect is surprisingly easy, doesn&#39;t require any additional DOM elements to be added through HTML, and falls back nicely for browsers that don&#39;t support CSS animations (it will just show up as a regular underline).</p> <p>The first thing we need to do is turn off <code>text-decoration</code>, and set the link&#39;s <code>position</code> to <code>relative</code>. For simplicitiy&#39;s sake, we&#39;ll also make sure the link doesn&#39;t change color on hover. Here we&#39;re applying the effect to all link elements inside <code>h2</code>s:</p> <div class="highlight"><pre><code class="language-css" data-lang="css"><span class="nt">h2</span> <span class="o">&gt;</span> <span class="nt">a</span> <span class="p">{</span> <span class="k">position</span><span class="o">:</span> <span class="k">relative</span><span class="p">;</span> <span class="k">color</span><span class="o">:</span> <span class="m">#000</span><span class="p">;</span> <span class="k">text-decoration</span><span class="o">:</span> <span class="k">none</span><span class="p">;</span> <span class="p">}</span> <span class="nt">h2</span> <span class="o">&gt;</span> <span class="nt">a</span><span class="nd">:hover</span> <span class="p">{</span> <span class="k">color</span><span class="o">:</span> <span class="m">#000</span><span class="p">;</span> <span class="p">}</span></code></pre></div> <p>Next, we want to add the border, and hide it through a transformation. We do this by inserting it with <code>:before</code>, and setting its X scale to <code>0</code>. As a fallback, we hide it with <code>visibility: hidden</code> for browsers that don&#39;t support CSS animations.</p> <div class="highlight"><pre><code class="language-css" data-lang="css"><span class="nt">h2</span> <span class="o">&gt;</span> <span class="nt">a</span><span class="nd">:before</span> <span class="p">{</span> <span class="k">content</span><span class="o">:</span> <span class="s2">&quot;&quot;</span><span class="p">;</span> <span class="k">position</span><span class="o">:</span> <span class="k">absolute</span><span class="p">;</span> <span class="k">width</span><span class="o">:</span> <span class="m">100%</span><span class="p">;</span> <span class="k">height</span><span class="o">:</span> <span class="m">2px</span><span class="p">;</span> <span class="k">bottom</span><span class="o">:</span> <span class="m">0</span><span class="p">;</span> <span class="k">left</span><span class="o">:</span> <span class="m">0</span><span class="p">;</span> <span class="k">background-color</span><span class="o">:</span> <span class="m">#000</span><span class="p">;</span> <span class="k">visibility</span><span class="o">:</span> <span class="k">hidden</span><span class="p">;</span> <span class="o">-</span><span class="n">webkit</span><span class="o">-</span><span class="n">transform</span><span class="o">:</span> <span class="n">scaleX</span><span class="p">(</span><span class="m">0</span><span class="p">);</span> <span class="n">transform</span><span class="o">:</span> <span class="n">scaleX</span><span class="p">(</span><span class="m">0</span><span class="p">);</span> <span class="o">-</span><span class="n">webkit</span><span class="o">-</span><span class="n">transition</span><span class="o">:</span> <span class="n">all</span> <span class="m">0.3s</span> <span class="n">ease</span><span class="o">-</span><span class="n">in</span><span class="o">-</span><span class="n">out</span> <span class="m">0s</span><span class="p">;</span> <span class="n">transition</span><span class="o">:</span> <span class="n">all</span> <span class="m">0.3s</span> <span class="n">ease</span><span class="o">-</span><span class="n">in</span><span class="o">-</span><span class="n">out</span> <span class="m">0s</span><span class="p">;</span> <span class="p">}</span></code></pre></div> <p>At the very bottom we tell the element to animate all changes applied to it, with a duration of <code>0.3</code> seconds. For the animation to appear, now we just need to make the element visible again on <code>hover</code>, and set its X scale back to <code>1</code>:</p> <div class="highlight"><pre><code class="language-css" data-lang="css"><span class="nt">h2</span> <span class="o">&gt;</span> <span class="nt">a</span><span class="nd">:hover:before</span> <span class="p">{</span> <span class="k">visibility</span><span class="o">:</span> <span class="k">visible</span><span class="p">;</span> <span class="o">-</span><span class="n">webkit</span><span class="o">-</span><span class="n">transform</span><span class="o">:</span> <span class="n">scaleX</span><span class="p">(</span><span class="m">1</span><span class="p">);</span> <span class="n">transform</span><span class="o">:</span> <span class="n">scaleX</span><span class="p">(</span><span class="m">1</span><span class="p">);</span> <span class="p">}</span></code></pre></div> <p>And that&#39;s it! Firefox has had support for <code>animation</code> and <code>transform</code> without the <code>moz</code> prefix <a href="http://caniuse.com/css-animation">since version 16.0</a> (for over a year), so I&#39;ve left out the prefix in the code. If you want to be safe, you should add <code>-o</code> and <code>-moz</code> to all animations and transforms.</p> Sat, 04 Jan 2014 10:46:00 +0000 http://tobiasahlin.com/blog/css-trick-animating-link-underlines http://tobiasahlin.com/blog/css-trick-animating-link-underlines We’ve become obsessed with process and tools <blockquote> <p>Caught up in a race for money and fame, we lost our focus on the important. We talk of venture capital, recruiting tactics, dreams of disrupting industries, stock options, growth hacks, and the superiority of our tools. We do not talk of the bugs, the quirks, the difficulties of using our creations, the exploitation of the public, or the worst secret of all: software is broken, we are responsible, and we’re making a lot of money off it.</p> <p>We’ve become obsessed with process and tools. We’ve stopped caring about the product.</p> </blockquote> <p>— <a href="http://warpspire.com/posts/product/">Kyle Neath, in &quot;Product&quot;</a></p> Sat, 04 Jan 2014 10:21:00 +0000 http://tobiasahlin.com/blog/product-obsessed-with-process-and-tools http://tobiasahlin.com/blog/product-obsessed-with-process-and-tools Poole <div class="size-960 banner-gray"> <img src="/static/poole.svg" alt="Poole" width="80" /> </div> <p><a href="http://markdotto.com/2014/01/02/introducing-poole/">Mark Otto</a>:</p> <blockquote> <p><a href="http://getpoole.com">Poole</a> is the Jekyll butler. It&#39;s a fully furnished Jekyll setup, designed to be a consistent and flexible starting point for Jekyll projects.</p> </blockquote> <p>I wish I would&#39;ve had Poole when I made the transition to <a href="http://pages.github.com">GitHub Pages</a> and <a href="http://jekyllrb.com">Jekyll</a>. Out of the box, it offers layouts, a custom 404 page, RSS feeds, posts, and an example page.</p> <p>Along with Poole, Mark released two excellent Jekyll themes today: <a href="https://github.com/poole/hyde">Hyde 2</a> and <a href="https://github.com/poole/lanyon">Lanyon</a>.</p> Thu, 02 Jan 2014 22:40:00 +0000 http://tobiasahlin.com/blog/poole-the-jekyll-butler http://tobiasahlin.com/blog/poole-the-jekyll-butler Master Your Typographic Adventures <div class="size-960 banner-orange"> <img src="/static/book.svg" alt="Book" width="90" /> </div> <p><a href="http://www.typogui.de">Benedikt Lehnert</a>:</p> <blockquote> <p>Typography is the craft of arranging type with the goal to make language visible. We’re arranging type multiple times throughout the day; whether it be writing essays, summarizing meeting minutes or creating slides for a presentation. What usually happens is, we end up thinking more about what we write than how we write it.</p> </blockquote> <p><a href="http://www.typogui.de">The guide</a> is beautifully illustrated. If you want to contribute, it&#39;s <a href="https://github.com/benediktlehnert/typopocketguide">available on GitHub</a>.</p> Wed, 01 Jan 2014 12:00:00 +0000 http://tobiasahlin.com/blog/typographic-pocket-guide http://tobiasahlin.com/blog/typographic-pocket-guide Button Shapes <blockquote> <p>It’s easy to design something attractive that’s not very usable, and it’s easy to design something usable that’s unattractive. The challenge is striking a balance, and iOS 7 made too many usability sacrifices to achieve attractiveness.</p> </blockquote> <p>— <a href="http://www.marco.org/2013/12/15/button-shapes">Marco Arment</a></p> Wed, 01 Jan 2014 04:00:00 +0000 http://tobiasahlin.com/blog/thoughts-on-button-shapes http://tobiasahlin.com/blog/thoughts-on-button-shapes Illusions (Part One) <iframe src="//player.vimeo.com/video/63609012?title=0&amp;byline=0&amp;portrait=0" width="960" height="409" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe> Wed, 01 Jan 2014 03:00:00 +0000 http://tobiasahlin.com/blog/illusions-part-one http://tobiasahlin.com/blog/illusions-part-one SpinKit <div class="spinkit-blog-showcase size-960"><div class="spinkit-spinner"></div></div> <p>While hacking away at <a href="/blog/infinite-scroll-with-jekyll/">Infinite Jekyll</a> the other week, I needed to show a loading indicator while fetching new posts. It had to be open-sourced though, and available in retina resolution. I couldn&#39;t find any decent spinners, so instead of sitting down in Photoshop and creating two GIFs, I turned to CSS animations and created a simple, repeatable, loading animation.</p> <p>Turns out, that was a ton of fun. I created a couple more, and have collected them in a set called <a href="/spinkit/">SpinKit</a>. They are all <a href="https://github.com/tobiasahlin/spinkit">available on GitHub</a>, and as <a href="/spinkit/">a separate showcase</a>, where it&#39;s easier to preview them and grab the source (pro tip: press S to show the source, ESC to close the popover.) </p> <p>They&#39;re easy to customize, animated with CSS transforms (they don&#39;t trigger redraws), and should run smoothly at 60fps on most setups, including iOS.</p> <p>Happy spinning!</p> Thu, 19 Dec 2013 17:50:00 +0000 http://tobiasahlin.com/blog/spinkit http://tobiasahlin.com/blog/spinkit Infinite Scroll With Jekyll <div class="size-960 banner-red"> <img src="/static/infinity.svg" alt="Infinity" width="190" /> </div> <p>If you want to use <a href="http://jekyllrb.com">Jekyll</a> but don&#39;t want to settle with a list of links to your blog posts, I just open sourced the parts that drives this blog&#39;s infinite scroll. As I mentioned in <a href="/blog/moving-from-wordpress-to-jekyll/">Moving from WordPress to Jekyll</a>, the implementation is built around collecting the links to all blog posts in a JSON file, and using that to load more posts as you scroll.</p> <p>If you&#39;d like to add this juicy feature to your Jekyll site, <a href="https://github.com/tobiasahlin/infinite-jekyll">head over to GitHub and grab the source</a>, and let&#39;s get started.</p> <h3>Adding the files</h3> <p>Add the <code>js</code> folder and <code>all-posts.json</code> to the root of your Jekyll site. If you&#39;re not already using jQuery, open <code>_layouts/default.html</code> and include it:</p> <div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;script </span><span class="na">src=</span><span class="s">&quot;//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js&quot;</span><span class="nt">&gt;&lt;/script&gt;</span></code></pre></div> <p>In <code>_layouts/default.html</code>, include <code>infinite-jekyll.js</code> after jQuery:</p> <div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;script </span><span class="na">src=</span><span class="s">&quot;/js/infinite-jekyll.js&quot;</span><span class="nt">&gt;&lt;/script&gt;</span></code></pre></div> <h3>Render posts, not links</h3> <p>How fun is it to only see links? Open up <code>index.html</code>. Find this line: </p> <div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;li&gt;&lt;span&gt;</span>{{ post.date | date_to_string }}<span class="nt">&lt;/span&gt;</span> <span class="ni">&amp;raquo;</span> <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">&quot;{{ post.url }}&quot;</span><span class="nt">&gt;</span>{{ post.title }}<span class="nt">&lt;/a&gt;&lt;/li&gt;</span></code></pre></div> <p>Remove everything within the <code>li</code>. Open up <code>_layouts/post.html</code> and copy the markup for single posts. Paste it within the <code>li</code>, and replace every instance of <code>page.</code> with <code>post.</code>. This is how it should look using the default markup:</p> <div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;li&gt;</span> <span class="nt">&lt;h2&gt;</span>{{ post.title }}<span class="nt">&lt;/h2&gt;</span> <span class="nt">&lt;p</span> <span class="na">class=</span><span class="s">&quot;meta&quot;</span><span class="nt">&gt;</span>{{ post.date | date_to_string }}<span class="nt">&lt;/p&gt;</span> <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">&quot;post&quot;</span><span class="nt">&gt;</span> {{ post.content }} <span class="nt">&lt;/div&gt;</span> <span class="nt">&lt;/li&gt;</span></code></pre></div> <h3>Limit the number of posts</h3> <p>Per default, Jekyll will render all posts in your entire archive. For lazy loading to make sense, we need to set a limit. Open up <code>index.html</code> and find this line:</p> <div class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="p">{</span><span class="o">%</span> <span class="k">for</span> <span class="n">post</span> <span class="k">in</span> <span class="n">site</span><span class="o">.</span><span class="n">posts</span> <span class="o">%</span><span class="p">}</span></code></pre></div> <p>Change it to:</p> <div class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="p">{</span><span class="o">%</span> <span class="k">for</span> <span class="n">post</span> <span class="k">in</span> <span class="n">site</span><span class="o">.</span><span class="n">posts</span> <span class="ss">limit</span><span class="p">:</span> <span class="mi">10</span> <span class="o">%</span><span class="p">}</span></code></pre></div> <p>You can change <code>10</code> to whatever number you like. The same number will be used for lazy loading new posts, so <code>10</code> will render 10 static post, and then fetch another 10 posts every time you get near the bottom of the page.</p> <h3>Add the spinner</h3> <p>You should see your 10 latest posts on the front page, but no infinite scroll yet. Infinite Jekyll will only try to lazy load posts if there&#39;s a spinner present. At the very end of <code>index.html</code>, add the spinner:</p> <div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">&quot;infinite-spinner&quot;</span><span class="nt">&gt;&lt;/div&gt;</span></code></pre></div> <p><code>spinner.css</code> contains a simple CSS spinner that works in most modern browsers. Open up <code>css/main.css</code>, and at the bottom, paste everything from <code>spinner.css</code>. </p> <p>And that should be it. If you&#39;re having any issues, <a href="http://twitter.com/tobiasahlin">ping me on twitter</a>, or create an issue <a href="https://github.com/tobiasahlin/infinite-jekyll">in the repo</a>. Happy scrolling!</p> Fri, 29 Nov 2013 15:50:00 +0000 http://tobiasahlin.com/blog/infinite-scroll-with-jekyll http://tobiasahlin.com/blog/infinite-scroll-with-jekyll Build Products That You Want To Use <blockquote> <p>There’s this belief that we must do a bunch of market research before we start making games. We have all these clever guys and we do all these focus groups. We get this perfect target audience, this guy, and then we build our games especially for him. But really at Blizzard we build the games we want to play. We build games that get us excited and are aesthetically pleasing to us.</p> </blockquote> <p>— Dustin Browder of Blizzard, in <a href="http://www.rockpapershotgun.com/2013/11/22/blizzard-on-heroes-of-the-storm-female-designs-in-mobas/">an interview about their new game, Heroes of the Storm</a>, answering the question &quot;What sort of crowd are you aiming to pull in?&quot;</p> Wed, 27 Nov 2013 13:10:00 +0000 http://tobiasahlin.com/blog/build-products-that-you-want-to-use http://tobiasahlin.com/blog/build-products-that-you-want-to-use Turn Off Pointer Events While Scrolling <p><a href="http://www.thecssninja.com/javascript/pointer-events-60fps">Ryan at The CSS Ninja explores</a> a <a href="https://twitter.com/derSchepp/statuses/400394164350644224">simple idea by Christian Schaefer</a>:</p> <blockquote> <p>Apply &quot;pointer-events: none&quot; to the <body> on scrollstart and remove it on scrollend.</p> </blockquote> <p>You&#39;ll be able to scroll without triggering any redraws. Clever.</p> Wed, 27 Nov 2013 13:00:00 +0000 http://tobiasahlin.com/blog/css-performance-hack http://tobiasahlin.com/blog/css-performance-hack