<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
	<title>A Beautiful Site</title>
	<subtitle>A boutique web development studio. Est. 2007</subtitle>
	
	<link href="https://www.abeautifulsite.net/feed/feed.xml" rel="self"/>
	<link href="https://www.abeautifulsite.net/"/>
	<updated>2026-09-23T00:00:00Z</updated>
	<id>https://www.abeautifulsite.net/</id>
	<author>
		<name>Cory LaViska</name>
		<email>cory@abeautifulsite.net</email>
	</author>
	
	<entry>
		<title>Copying a File Path in Finder</title>
		<link href="https://www.abeautifulsite.net/posts/copying-a-file-path-in-finder/"/>
		<updated>2026-09-23T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/copying-a-file-path-in-finder/</id>
		<content type="html">&lt;p&gt;I keep discovering macOS features I should&#39;ve known about for years.&lt;/p&gt;
&lt;p&gt;Need a file&#39;s full pathname? For a long time I was right clicking, opening &lt;em&gt;Get Info&lt;/em&gt;, highlighting the path, and copying it. That&#39;s a lot of clicks for something I do many times a day. Yet I&#39;ve somehow continued on like this for years…&lt;/p&gt;
&lt;p&gt;I&#39;ve known about the &lt;kbd&gt;Option&lt;/kbd&gt; key menu trick in macOS, but I never knew that right-clicking a file in Finder and holding &lt;kbd&gt;Option&lt;/kbd&gt; would turn the &lt;em&gt;Copy&lt;/em&gt; action into &lt;em&gt;Copy &amp;quot;filename&amp;quot; as Pathname&lt;/em&gt;. 🤯&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/copy-as-pathname.jpg&quot; alt=&quot;Screenshot of Finder&#39;s context menu with Copy &amp;quot;test.html&amp;quot; as Pathname highlighted after holding Option&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This probably isn&#39;t news to everyone, but I&#39;ve been a macOS user for longer than I care to admit and I just now discovered it.&lt;/p&gt;
&lt;p&gt;Naturally, I &lt;a href=&quot;https://bsky.app/profile/cory.laviska.com/post/3mw76wulpwc2b&quot;&gt;posted about it on Bluesky&lt;/a&gt; and &lt;a href=&quot;https://bsky.app/profile/dpom.bsky.social/post/3mw7wsdzsts2j&quot;&gt;Dusty chimed in&lt;/a&gt; to tell me that you can press &lt;kbd&gt;⌘&lt;/kbd&gt; + &lt;kbd&gt;Option&lt;/kbd&gt; + &lt;kbd&gt;C&lt;/kbd&gt; to do the same thing with the keyboard.&lt;/p&gt;
&lt;p&gt;What other obvious shortcuts have I been missing out on?!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Named Breakpoints Without Sass</title>
		<link href="https://www.abeautifulsite.net/posts/named-breakpoints-without-sass/"/>
		<updated>2026-09-22T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/named-breakpoints-without-sass/</id>
		<content type="html">&lt;p&gt;I stopped using Sass awhile ago. &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Nesting&quot;&gt;CSS nesting&lt;/a&gt; and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Cascading_variables/Using_custom_properties&quot;&gt;custom properties&lt;/a&gt; cover almost everything I used it for. It&#39;s been liberating to not have a build step for my CSS.*&lt;/p&gt;
&lt;p&gt;But I do miss named breakpoints. In Sass, for example, you could set &lt;code&gt;$md: 48em&lt;/code&gt; and use it in all your &lt;code&gt;@media&lt;/code&gt; queries.&lt;/p&gt;
&lt;pre class=&quot;language-scss&quot;&gt;&lt;code class=&quot;language-scss&quot;&gt;&lt;span class=&quot;token property&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$md&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 48em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;min-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$md&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  ...
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Early on, custom properties looked like they&#39;d be the holy grail for this! Alas…&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;:root&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;--breakpoint-md&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 48em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;min-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--breakpoint-md&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* lol nope */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I assumed this was an oversight that would get fixed eventually. Turns out, it was intentional.&lt;/p&gt;
&lt;h2 id=&quot;%22why-can&#39;t-it-just-read-the-value-from-%3Aroot%3F%22&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/named-breakpoints-without-sass/#%22why-can&#39;t-it-just-read-the-value-from-%3Aroot%3F%22&quot;&gt;&amp;quot;Why can&#39;t it just read the value from :root?&amp;quot;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The problem is that custom properties are element-scoped. They cascade and inherit like any other property, but their values aren&#39;t known until the browser computes styles for a specific element.&lt;/p&gt;
&lt;p&gt;A media query is, well, not an element. It&#39;s evaluated against the viewport &lt;em&gt;before&lt;/em&gt; the cascade runs, so there&#39;s no element to read &lt;code&gt;--breakpoint-md&lt;/code&gt; from, and using &lt;code&gt;:root&lt;/code&gt; would have been a malformed bastardization of the specification.*&lt;/p&gt;
&lt;p&gt;The objection was scoping and evaluation order, but knowing why doesn&#39;t make it any less disappointing.&lt;/p&gt;
&lt;h2 id=&quot;the-proposals&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/named-breakpoints-without-sass/#the-proposals&quot;&gt;The Proposals&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are two proposals to help with this problem, but neither has shipped.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://drafts.csswg.org/mediaqueries-5/#custom-mq&quot;&gt;&lt;code&gt;@custom-media&lt;/code&gt;&lt;/a&gt; from Media Queries Level 5 lets you name an entire query and reuse it.&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@custom-media&lt;/span&gt; --tablet &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;width &gt;= 48em&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--tablet&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  ...
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The spec has been around for years. Firefox has it &lt;a href=&quot;https://caniuse.com/mdn-css_at-rules_custom-media&quot;&gt;behind a flag&lt;/a&gt;, and Chrome and Safari haven&#39;t shipped it at all. It also names a &lt;em&gt;query&lt;/em&gt;, not a length, so you can&#39;t reuse the same number in a &lt;code&gt;width&lt;/code&gt; property somewhere else.&lt;/p&gt;
&lt;p&gt;Author-defined &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/env&quot;&gt;&lt;code&gt;env()&lt;/code&gt;&lt;/a&gt; variables are closer to what I actually want. Unlike custom properties, environment variables are global and don&#39;t cascade, which is why they&#39;re allowed in media queries. Browsers provide a few, like &lt;code&gt;safe-area-inset-top&lt;/code&gt;, but there&#39;s no way for authors to define their own yet. The spec is a &lt;a href=&quot;https://www.w3.org/TR/css-env-1/&quot;&gt;working draft&lt;/a&gt; as of 2025, and how you&#39;d even declare one is still up in the air.&lt;/p&gt;
&lt;h2 id=&quot;a-clever-solution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/named-breakpoints-without-sass/#a-clever-solution&quot;&gt;A Clever Solution&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I stumbled upon &lt;a href=&quot;https://bsky.app/profile/mastrojs.bsky.social/post/3mw3kv5djic2q&quot;&gt;this post by Mastro&lt;/a&gt;, which pointed at &lt;a href=&quot;https://codepen.io/walpolea/pen/vYMLjaz&quot;&gt;Andrew Walpole&#39;s CodePen&lt;/a&gt;. The idea is you write the viewport sizes in &lt;code&gt;@media&lt;/code&gt;, set a named token on &lt;code&gt;:root&lt;/code&gt;, and access it with a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_containment/Container_size_and_style_queries&quot;&gt;style query&lt;/a&gt; instead of repeating the media query.&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;:root&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;--viewport&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;desktop&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;max-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 64em&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;--viewport&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;tablet&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;max-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 37.5em&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;--viewport&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;mobile&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@container&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;--viewport&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;mobile&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* Styles for the mobile bucket */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@container&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;--viewport&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;desktop&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
@container &lt;span class=&quot;token function&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;--viewport&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;tablet&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* Styles for everything bigger */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This isn&#39;t a real viewport query, of course. It&#39;s a style query that happens to track one, and style queries for custom properties only landed in Firefox 151 back in May, so anyone on an older version &lt;a href=&quot;https://caniuse.com/css-container-queries-style&quot;&gt;won&#39;t get them&lt;/a&gt;. It&#39;s definitely a neat trick, though!&lt;/p&gt;
&lt;p&gt;Unfortunately, there&#39;s no clean fallback for unsupportive browsers. &lt;code&gt;@supports&lt;/code&gt; &lt;a href=&quot;https://www.bram.us/2026/03/15/at-rule/&quot;&gt;can&#39;t detect style queries&lt;/a&gt;, and even if it could, the only workaround would be to duplicate everything in &lt;code&gt;@media&lt;/code&gt;. 😕&lt;/p&gt;
&lt;p&gt;So it&#39;s a bit &lt;em&gt;too&lt;/em&gt; early to use for production, but it will soon be a good reason to &lt;em&gt;not&lt;/em&gt; keep a preprocessor around.&lt;/p&gt;
&lt;hr /&gt;
&lt;small&gt;
&lt;p&gt;*Sass is &lt;a href=&quot;https://lists.w3.org/Archives/Public/www-style/2015Jul/0147.html&quot;&gt;one of the reasons&lt;/a&gt; we got &lt;code&gt;--&lt;/code&gt; instead of &lt;code&gt;$&lt;/code&gt; and I&#39;ve seriously thought about making my own preprocessor because it&#39;s so awkward. But I really, really don&#39;t want a build step for my CSS.&lt;/p&gt;
&lt;/small&gt;
</content>
	</entry>
	
	<entry>
		<title>I&#39;d Rather Review Specs</title>
		<link href="https://www.abeautifulsite.net/posts/id-rather-review-specs/"/>
		<updated>2026-09-16T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/id-rather-review-specs/</id>
		<content type="html">&lt;p&gt;From a maintainer&#39;s perspective, AI-generated pull requests are just piles of potential slop that we have to sort through. We have no idea if folks are one-shotting them or if they&#39;re taking the time to spec out proper solutions and mold them into usable code.&lt;/p&gt;
&lt;p&gt;That uncertainty isn&#39;t free. It costs review time, which is the one thing maintainers never have enough of. &lt;a href=&quot;https://daniel.haxx.se/blog/2025/07/14/death-by-a-thousand-slops/&quot;&gt;Daniel Stenberg&lt;/a&gt; has been feeling this same pain with curl.&lt;/p&gt;
&lt;p&gt;I would much rather folks help spec out the features and improvements they want to see in the library, as that&#39;s much easier to review and a thousand times more useful than generating a bunch of code.&lt;/p&gt;
&lt;p&gt;Send me the thinking. Not the slop.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Most Software Was Already Slop</title>
		<link href="https://www.abeautifulsite.net/posts/most-software-was-already-slop/"/>
		<updated>2026-09-04T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/most-software-was-already-slop/</id>
		<content type="html">&lt;p&gt;As software engineers, we take pride in hand-written code and knowing how everything we build works in detail. While there are many developers out there who build good software, there are many, many more who don’t. Yet we balk at the idea of &lt;a href=&quot;https://en.wikipedia.org/wiki/Vibe_coding&quot;&gt;vibe coding&lt;/a&gt;, even when it yields decent results.&lt;/p&gt;
&lt;p&gt;You don’t need a scientific study to realize the mean quality of human-authored software leaned towards slop even before AI was around. How many times have you been frustrated by an app or website that just didn’t work right? (This is especially true for software produced by big companies.)&lt;/p&gt;
&lt;p&gt;The quality of software humans &lt;em&gt;can build&lt;/em&gt; is absolutely incredible. But the quality of software humans actually &lt;em&gt;do build&lt;/em&gt; is usually not.&lt;/p&gt;
&lt;p&gt;So no, AI can’t build perfect software. Maybe that will improve in the future, or maybe it will remain just as messy as the human-authored code LLMs have been trained on. I don’t think any of that matters, because if AI can build software that’s at least as good as the mediocre code that came before it, that will be acceptable for most industries.&lt;/p&gt;
&lt;p&gt;Customers don’t care about the craft, they care about the result. And if the result is faster, cheaper, and good enough…well, that’s a better combination than anything they’ve ever had before. Why wouldn&#39;t they choose it?&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.workchronicles.com/p/comic-fast-good-cheap&quot;&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/work-chronicles-good-fast-cheap.png&quot; alt=&quot;Work Chronicles comic: Fast, Good, Cheap&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>FOUCE Should Be the Browser&#39;s Problem</title>
		<link href="https://www.abeautifulsite.net/posts/fouce-should-be-the-browsers-problem/"/>
		<updated>2026-08-20T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/fouce-should-be-the-browsers-problem/</id>
		<content type="html">&lt;p&gt;I&#39;ve already written about &lt;a href=&quot;https://www.abeautifulsite.net/posts/flash-of-undefined-custom-elements&quot;&gt;FOUCE&lt;/a&gt; &lt;a href=&quot;https://www.abeautifulsite.net/posts/revisiting-fouce&quot;&gt;twice&lt;/a&gt;…it&#39;s that annoying &lt;mark&gt;Flash of Unstyled Custom Element&lt;/mark&gt; that occurs when the page first loads. It&#39;s one of the most common complaints from folks who use web components.&lt;/p&gt;
&lt;p&gt;And while the proposed solution works in practice, it&#39;s not exactly ergonomic:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cloak the page with a class and a CSS rule&lt;/li&gt;
&lt;li&gt;List every custom element by name&lt;/li&gt;
&lt;li&gt;Wait for all of them to register (and use a &lt;code&gt;setTimeout()&lt;/code&gt; as a fallback)&lt;/li&gt;
&lt;li&gt;Remove the class with JS to reveal the page&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Since we&#39;re a bit limited with what we can do in userland, I began pondering what browsers &lt;em&gt;could&lt;/em&gt; do to solve such a problem.&lt;/p&gt;
&lt;p&gt;What if we could register custom elements like this?*&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;element&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;my-button.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When such a script is on the page, the browser would load the custom element from the module, wait until it fully resolves and registers, and &lt;em&gt;then&lt;/em&gt; paint. That means zero FOUCE out of the box, and browsers could even take it a step further and guarantee those elements are available immediately, removing the need for &lt;code&gt;await customElements.whenDefined()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Every custom element defined this way would become a first-class citizen, just like native HTML elements.&lt;/p&gt;
&lt;h2 id=&quot;%E2%80%9Cbut-we-already-have-blocking%3Drender%E2%80%9D&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/fouce-should-be-the-browsers-problem/#%E2%80%9Cbut-we-already-have-blocking%3Drender%E2%80%9D&quot;&gt;“But We Already Have &lt;code&gt;blocking=render&lt;/code&gt;”&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/script&quot;&gt;&lt;code&gt;blocking=&amp;quot;render&amp;quot;&lt;/code&gt;&lt;/a&gt; attribute tells the browser to hold off painting until the script has been fetched and executed. If your file is a flat module that calls &lt;code&gt;customElements.define()&lt;/code&gt; at the top level, this works today:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;module&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;my-button.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;blocking&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;render&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Alas, that&#39;s not how most component libraries are built. Registration tends to happen behind an &lt;code&gt;await&lt;/code&gt;, e.g. a dynamic import or a lazy loader that defines elements as it finds them in the DOM. The module finishes executing before the elements are defined, so the browser paints and, well, we&#39;re right back where we started. 😕&lt;/p&gt;
&lt;p&gt;The problem is that &lt;code&gt;blocking=&amp;quot;render&amp;quot;&lt;/code&gt; cares about &lt;em&gt;scripts&lt;/em&gt;, but FOUCE is about &lt;em&gt;custom elements&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;changing-the-spec&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/fouce-should-be-the-browsers-problem/#changing-the-spec&quot;&gt;Changing the Spec&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I know this isn&#39;t a fast or easy thing to change but, at the moment, every project that wants to avoid FOUCE has to discover the problem, find a solution, and wire it all up correctly. That&#39;s a lot to ask for something the browser could easily handle on its own, and it&#39;s a big reason people reach for SSR or, more commonly, decide against using web components.&lt;/p&gt;
&lt;p&gt;I&#39;m not married to this proposed syntax, but I do hope this inspires browser makers to give us a sensible way to prevent FOUCE. This would&lt;/p&gt;
&lt;p&gt;The browser already knows when custom elements get defined, it just won&#39;t let us wait for them.&lt;/p&gt;
&lt;hr /&gt;
&lt;small&gt;
&lt;p&gt;*I considered &lt;code&gt;&amp;lt;link rel=&amp;quot;element&amp;quot; href=&amp;quot;my-button.js&amp;quot;&amp;gt;&lt;/code&gt;, but since custom elements are defined in JavaScript where other potentially unrelated logic can execute, it&#39;s seems &lt;code&gt;&amp;lt;script type=&amp;quot;element&amp;quot;&amp;gt;&lt;/code&gt; is more appropriate.&lt;/p&gt;
&lt;/small&gt;
</content>
	</entry>
	
	<entry>
		<title>Contextual Styling With CSS Nesting</title>
		<link href="https://www.abeautifulsite.net/posts/contextual-styling-with-css-nesting/"/>
		<updated>2026-08-12T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/contextual-styling-with-css-nesting/</id>
		<content type="html">&lt;p&gt;I&#39;ve been hooked on &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_nesting&quot;&gt;CSS nesting&lt;/a&gt; for awhile. Like Sass, I&#39;ve always written it with the &lt;code&gt;&amp;amp;&lt;/code&gt; selector at the front, like this.&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.button&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; slategrey&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token selector&quot;&gt;&amp;amp;:hover&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; darkslategrey&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Turns out, the &lt;code&gt;&amp;amp;&lt;/code&gt; doesn&#39;t have to come first. Put it &lt;em&gt;after&lt;/em&gt; another selector and the relationship flips. Instead of styling what&#39;s inside the element, you&#39;re styling the element based on what surrounds it.&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; white&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; black&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;/* When the card is inside a dark container */&lt;/span&gt;
  &lt;span class=&quot;token selector&quot;&gt;.dark &amp;amp;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #1c1e21&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; white&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That compiles to the equivalent of this.&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; white&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; black&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;.dark .card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #1c1e21&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; white&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Read &lt;code&gt;.dark &amp;amp;&lt;/code&gt; as &amp;quot;when this element is inside &lt;code&gt;.dark&lt;/code&gt;.&amp;quot; The card&#39;s default styles and its dark mode styles now live in the same rule. This is handy for components that adapt to their container. Here&#39;s a button that slims down when it lands in a toolbar.&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.button&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.875rem 1.125rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token selector&quot;&gt;.toolbar &amp;amp;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.375rem 0.625rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And since &lt;code&gt;&amp;amp;&lt;/code&gt; is just a selector like any other, you can use it more than once. This adds spacing between adjacent cards.&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.card&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; solid 1px lightgray&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.5rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token selector&quot;&gt;&amp;amp; + &amp;amp;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;margin-top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The caveat is specificity. Under the hood, the browser replaces &lt;code&gt;&amp;amp;&lt;/code&gt; with the parent selector wrapped in &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/:is&quot;&gt;&lt;code&gt;:is()&lt;/code&gt;&lt;/a&gt;, so &lt;code&gt;.dark &amp;amp;&lt;/code&gt; becomes &lt;code&gt;.dark :is(.card)&lt;/code&gt;. That matters because &lt;code&gt;:is()&lt;/code&gt; takes the specificity of its most specific argument, which can bite you if the parent rule uses a selector list.&lt;/p&gt;
&lt;p&gt;If you&#39;ve used Sass, this trick probably looks familiar because it&#39;s worked there for ages. &lt;em&gt;The two aren&#39;t quite the same underneath, though.&lt;/em&gt; Sass pastes the parent selector in as text, so &lt;code&gt;&amp;amp;&lt;/code&gt; inherits whatever specificity that text happens to have.&lt;/p&gt;
&lt;p&gt;Native CSS wraps it in &lt;code&gt;:is()&lt;/code&gt; instead, which is where the selector list gotcha comes from. The examples here land in the same place either way, but the moment an ID shows up in the parent, the two stop agreeing.&lt;/p&gt;
&lt;p&gt;The good news is that &lt;a href=&quot;https://caniuse.com/css-nesting&quot;&gt;browser support for native nesting&lt;/a&gt; is green across the board now, so you don&#39;t need a preprocessor for it anymore.&lt;/p&gt;
&lt;p&gt;That&#39;s one less reason to reach for a build step when writing CSS.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>I&#39;m pulling ColorCopy from the macOS App Store</title>
		<link href="https://www.abeautifulsite.net/posts/im-pulling-colorcopy-from-the-macos-app-store/"/>
		<updated>2026-08-07T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/im-pulling-colorcopy-from-the-macos-app-store/</id>
		<content type="html">&lt;p&gt;I launched &lt;a href=&quot;https://colorcopy.app/&quot;&gt;ColorCopy&lt;/a&gt; on May 18. It was my second macOS app, but the first one I launched on the &lt;a href=&quot;https://www.abeautifulsite.net/posts/introducing-colorcopy&quot;&gt;Mac App Store&lt;/a&gt;. Today, I decided to pull it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/colorcopy/colorcopy-mac-app-store-listing.png&quot; alt=&quot;ColorCopy Pro&#39;s listing on the Mac App Store&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The app isn&#39;t a new idea, but it bakes four color tools into a single menu bar app: an eyedropper, a color picker, a palette manager, and a contrast checker, each one a hotkey away.&lt;/p&gt;
&lt;p&gt;I made it available for free, with a one-time in-app purchase to unlock unlimited use. No subscription, no recurring fees. It&#39;s simple, stable software with the lowest possible barrier to entry…exactly the kind of utility the App Store seems made for.&lt;/p&gt;
&lt;p&gt;I wasn&#39;t sure what to expect, so I ran an experiment to answer some questions:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Is there any real benefit to having your Mac app on the App Store? Is the Apple tax worth it? Will customers just come flooding in?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;mark&gt;For ColorCopy&#39;s release, I did zero marketing.&lt;/mark&gt; No Product Hunt launch. No Hacker News post. The only things I published were &lt;a href=&quot;https://www.abeautifulsite.net/posts/introducing-colorcopy/&quot;&gt;this blog post&lt;/a&gt; and &lt;a href=&quot;https://x.com/abeautifulsite/status/2056555538104598839&quot;&gt;a tweet&lt;/a&gt;. If the App Store delivers on its promise of discoverability, that should be enough to see &lt;em&gt;some&lt;/em&gt; kind of traffic…right?&lt;/p&gt;
&lt;p&gt;You be the judge. In nearly three months on the App Store, ColorCopy got a little over 1,000 impressions, 149 product page views, 85 first-time downloads, three in-app purchases, and $21 in proceeds. Not per day. &lt;em&gt;In total.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/colorcopy/colorcopy-app-store-analytics.png&quot; alt=&quot;ColorCopy&#39;s all-time App Store analytics: 85 first-time downloads, 1.06K impressions, 149 product page views, 3 in-app purchases, and $21 in proceeds&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Broken down over 81 days, that averages out to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;13 impressions per day&lt;/li&gt;
&lt;li&gt;1.8 product page views per day&lt;/li&gt;
&lt;li&gt;1 download per day&lt;/li&gt;
&lt;li&gt;0.04 in-app purchases per day (about one per month)&lt;/li&gt;
&lt;li&gt;$0.26 in proceeds per day&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Extrapolated to 12 months, ColorCopy would have earned about $95…not even enough to cover Apple&#39;s $99 annual developer fee.&lt;/p&gt;
&lt;p&gt;If discoverability isn&#39;t a part of the App Store deal, what exactly is the benefit? Why limit your Mac app to the sandbox?* Why spend hours in App Store Connect filling out metadata, screenshots, and localization information? Why wait an arbitrary number of days for someone to review your app with the consistency of a coin flip?&lt;/p&gt;
&lt;p&gt;It doesn&#39;t seem worth it for Mac developers.&lt;/p&gt;
&lt;h2 id=&quot;adios%2C-app-store-%F0%9F%91%8B&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/im-pulling-colorcopy-from-the-macos-app-store/#adios%2C-app-store-%F0%9F%91%8B&quot;&gt;Adios, App Store 👋&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As of today, ColorCopy is self-distributed and sold through &lt;a href=&quot;https://polar.sh/&quot;&gt;Polar&lt;/a&gt; (the new Stripe, which I highly recommend). This is the same way I sell &lt;a href=&quot;https://tonguetype.app/&quot;&gt;TongueType&lt;/a&gt;, which makes pretty much everything easier on my end: one dashboard, real customer relationships, no finicky review process, and updates ship the moment they&#39;re ready.&lt;/p&gt;
&lt;p&gt;The move required swapping out in-app purchases from StoreKit to Polar, and updates now ship through &lt;a href=&quot;https://sparkle-project.org/&quot;&gt;Sparkle&lt;/a&gt; instead of the App Store&#39;s built-in update mechanism. Both are tried and true solutions for self-distributed Mac apps.&lt;/p&gt;
&lt;p&gt;To be fair, you can&#39;t really do this on iOS. Most users aren&#39;t jailbroken…walled garden and all. But on Mac, where self-distribution is still a first-class option, there seems to be zero incentive to be in the App Store, especially if you&#39;re counting on discoverability.&lt;/p&gt;
&lt;p&gt;In three months, the App Store sent me barely a trickle of customers. Had I marketed the app myself, the traffic would have flowed the other way. I would&#39;ve been sending &lt;em&gt;my&lt;/em&gt; customers to Apple and paying a tax for the privilege.** Self-distribution gives me the freedom and control over my apps that the App Store&#39;s sandbox never will.&lt;/p&gt;
&lt;p&gt;If it&#39;s on me to drum up all of my own traffic, I&#39;m going to send it to my own website.&lt;/p&gt;
&lt;hr /&gt;
&lt;small&gt;
&lt;p&gt;*I originally used a &lt;a href=&quot;https://github.com/danielcapra/SCColorSampler&quot;&gt;third-party library&lt;/a&gt; for the eye dropper because &lt;code&gt;NSColorSampler&lt;/code&gt; is meh, but the sandbox forbids it so I was forced to remove it. Yes, I had to make my app shittier in order to put it on the App Store.&lt;/p&gt;
&lt;p&gt;**I fully acknowledge this may not be the case for every app, but it was my experience and worth sharing. Your mileage may vary.&lt;/p&gt;
&lt;p&gt;Aside: ColorCopy was available in 10 languages on the App Store. For some reason, the listing always showed FR as its primary language (it wasn&#39;t). The app is available in many languages, including English.&lt;/p&gt;
&lt;/small&gt;
</content>
	</entry>
	
	<entry>
		<title>Software Has Changed</title>
		<link href="https://www.abeautifulsite.net/posts/software-has-changed/"/>
		<updated>2026-07-12T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/software-has-changed/</id>
		<content type="html">&lt;p&gt;&lt;a href=&quot;https://x.com/jamonholmgren/status/2075981153564348512?ref_src=twsrc%5Etfw&quot;&gt;A tweet&lt;/a&gt; from &lt;a href=&quot;https://x.com/jamonholmgren&quot;&gt;Jamon Holmgren&lt;/a&gt; inspired some thoughts about how software has changed, from a developer&#39;s perspective. He says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I&#39;ve been spending a lot of time talking to experienced software engineers lately and when you get in a 1:1 candid conversation, everyone is rather shell-shocked by how quickly and drastically things have changed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It&#39;s true.&lt;/p&gt;
&lt;p&gt;We&#39;re building faster, but not necessarily better. We&#39;re building more, but not necessarily more of the right things. We&#39;ve traded flow states for &amp;quot;thinking…&amp;quot; states. We throw away code without a thought because experiments are cheap.&lt;/p&gt;
&lt;p&gt;But that also means the good devs do more. We&#39;re not exhausted from writing every piece of code by hand, so we have the time and energy to review, polish, refactor, and add those extra features. We can solve technical debt before it ever lands in &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I still love this field, but it changed overnight. It&#39;s not the world I chose to live in, but I&#39;m making the best of it and learning to build faster than I could before. I think at a higher level now, and that helps avoid tunnel vision.&lt;/p&gt;
&lt;p&gt;A question I find myself pondering: if the end result is solid code that I&#39;ve thoroughly reviewed and trust, does it truly matter how it was created?&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>I Mostly Stopped Typing</title>
		<link href="https://www.abeautifulsite.net/posts/i-mostly-stopped-typing/"/>
		<updated>2026-06-25T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/i-mostly-stopped-typing/</id>
		<content type="html">&lt;p&gt;I built the dictation app &lt;em&gt;I&lt;/em&gt; wanted. It&#39;s called &lt;a href=&quot;https://tonguetype.app/&quot;&gt;TongueType&lt;/a&gt;, and my daughter did the voice over for the video. (Family business.)&lt;/p&gt;
&lt;p&gt;It hasn&#39;t gotten much traction yet, and I think I know why. Dictation was bad for so long that most people stopped paying attention. I don&#39;t blame them. I wrote it off myself for years.&lt;/p&gt;
&lt;p&gt;Alas, that reputation is out of date. The thing that was flaky and frustrating five years ago runs entirely on your Mac now, and it&#39;s good. &lt;em&gt;Really good.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Downloads of the app are low so far, but the people who actually try it tend to stick around. So the problem isn&#39;t the app, it&#39;s getting anyone to give dictation one more chance.&lt;/p&gt;
&lt;h2 id=&quot;the-habit-is-the-hurdle&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/i-mostly-stopped-typing/#the-habit-is-the-hurdle&quot;&gt;The habit is the hurdle&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The hard part isn&#39;t accuracy. It&#39;s that talking instead of typing is a new habit, and new habits are awkward before they&#39;re automatic. For the first week it feels strange. You catch yourself reaching for the keyboard out of muscle memory.&lt;/p&gt;
&lt;p&gt;Then one day it clicks.&lt;/p&gt;
&lt;p&gt;I still write code by hand. That&#39;s thinking, not transcribing, and I want my fingers on it (plus saying HTML tags and attributes out loud seems counterintuitive 😂). But for almost everything else, I talk.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I prompt LLMs&lt;/li&gt;
&lt;li&gt;I send emails&lt;/li&gt;
&lt;li&gt;I reply on Slack&lt;/li&gt;
&lt;li&gt;I write commit messages&lt;/li&gt;
&lt;li&gt;I do most other text with my voice&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Every one of those is the same task: the thinking is done, I just have to get the words out. That&#39;s a bigger chunk of my day than I expected.&lt;/p&gt;
&lt;h2 id=&quot;my-desk-setup&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/i-mostly-stopped-typing/#my-desk-setup&quot;&gt;My desk setup&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;On the go, the MacBook&#39;s built-in mic works just fine. You don&#39;t need fancy hardware for this. But when I&#39;m at my desk, my laptop is docked, so I pair TongueType with a &lt;a href=&quot;https://tulamics.com/&quot;&gt;Tula mic&lt;/a&gt;. It&#39;s small, portable, sounds great, and looks the part! (&lt;a href=&quot;https://www.unibrands.co/collections/kuru-toga&quot;&gt;Kuru Toga&lt;/a&gt; mechanical pencil positioned for size comparison.)&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/tula-mic.webp&quot; alt=&quot;A Tula microphone on a stand in front of a monitor, with a blue pen in the foreground for scale&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;One tip:&lt;/em&gt; use a wired mic if you can. Bluetooth adds latency, and latency is the enemy of a tool you reach for dozens of times a day.&lt;/p&gt;
&lt;p&gt;Honest caveat: dictation probably isn&#39;t great in a co-working space. 😂&lt;/p&gt;
&lt;h2 id=&quot;%22why-is-this-better-than-macos-dictation%3F%22&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/i-mostly-stopped-typing/#%22why-is-this-better-than-macos-dictation%3F%22&quot;&gt;&amp;quot;Why is this better than macOS dictation?&amp;quot;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;TongueType is more accurate, it&#39;s more customizable, and it doesn&#39;t send my voice anywhere.&lt;/p&gt;
&lt;p&gt;I could list the features, but my answer is the same one I&#39;d give for most things: &lt;a href=&quot;https://tonguetype.app/&quot;&gt;just try it&lt;/a&gt;. It&#39;s free to start.&lt;/p&gt;
&lt;p&gt;What&#39;s &lt;em&gt;your&lt;/em&gt; experience been with dictation? If you wrote it off years ago, I&#39;d genuinely love for you to give &lt;a href=&quot;https://tonguetype.app/&quot;&gt;TongueType&lt;/a&gt; a shot and tell me what you think.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Introducing ColorCopy</title>
		<link href="https://www.abeautifulsite.net/posts/introducing-colorcopy/"/>
		<updated>2026-05-18T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/introducing-colorcopy/</id>
		<content type="html">&lt;p&gt;My second macOS app, &lt;a href=&quot;https://colorcopy.app/&quot;&gt;ColorCopy&lt;/a&gt;, was approved by the Mac App Store today! It started as a menu bar color picker. Press a key, click any pixel on your screen, and the color lands on your clipboard in whatever format you need.&lt;/p&gt;
&lt;p&gt;Then I kept finding more things I wanted to put into it.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Update (August 2026): ColorCopy is no longer on the Mac App Store. It&#39;s now self-distributed and available at &lt;a href=&quot;https://colorcopy.app/&quot;&gt;ColorCopy.app&lt;/a&gt;. &lt;a href=&quot;https://www.abeautifulsite.net/posts/im-pulling-colorcopy-from-the-macos-app-store/&quot;&gt;Here&#39;s why I pulled it.&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; margin-block: 3rem;&quot;&gt;
  &lt;a href=&quot;https://colorcopy.app/&quot;&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/colorcopy/colorcopy-app-icon.png&quot; alt=&quot;The ColorCopy app icon&quot; width=&quot;128&quot; height=&quot;128&quot; style=&quot;border-radius: 22.5%;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id=&quot;why-i-made-it&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/introducing-colorcopy/#why-i-made-it&quot;&gt;Why I made it&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I pick colors off my screen constantly. A shade in a screenshot, a brand color on a website, an accent color in an app I want to match.&lt;/p&gt;
&lt;p&gt;There are plenty of color picker apps already, so &lt;em&gt;why build another one?&lt;/em&gt; Because picking colors is the easy part. I also wanted to compare contrast ratios, keep my palettes organized, pull colors out of an image, and sync all of it between my Macs. Doing that meant opening four different tools.&lt;/p&gt;
&lt;p&gt;Plus, I enjoy building my own tools!&lt;/p&gt;
&lt;h2 id=&quot;how-it-works&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/introducing-colorcopy/#how-it-works&quot;&gt;How it works&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Press the hotkey, click any pixel on screen, and the color is formatted and written to your clipboard. There are four configurable global hotkeys: pick a color instantly, open the Color Picker window, open your palettes, or open the contrast checker.&lt;/p&gt;
&lt;p&gt;The Color Picker window has an eyedropper and shows the selected color in all 21 formats at once. Click a row to copy it. It&#39;s the format converter I always wanted.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/colorcopy/colorcopy-color-picker.jpg&quot; alt=&quot;ColorCopy&#39;s Color Picker window: a visual hue and saturation picker beside a list of color formats&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;palettes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/introducing-colorcopy/#palettes&quot;&gt;Palettes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A color picker that forgets every color the moment you copy it isn&#39;t much of a tool. ColorCopy keeps a configurable history of recent picks and a full palette manager.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/colorcopy/colorcopy-palettes.jpg&quot; alt=&quot;ColorCopy&#39;s palette manager, showing color scales organized into named palettes&quot; /&gt;&lt;/p&gt;
&lt;p&gt;There are 24 built-in presets, including Tailwind, Material Design 3, Radix Colors, Open Color, IBM Carbon, GitHub Primer, and Apple System Colors. You can build unlimited custom palettes, organize them into named scales, and drag swatches around.&lt;/p&gt;
&lt;p&gt;Star any swatch and it shows up under a Favorites submenu right in the menu bar. One click and that exact color is on your clipboard.&lt;/p&gt;
&lt;p&gt;You can also extract a palette from any image by dragging one onto the window. Choose how many colors to pull and it saves the result as a new palette.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/colorcopy/colorcopy-palette-from-image.jpg&quot; alt=&quot;ColorCopy&#39;s New Palette from Image dialog, extracting colors from a photograph&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Palettes import from Adobe Swatch Exchange (&lt;code&gt;.ase&lt;/code&gt;), Apple Color List (&lt;code&gt;.clr&lt;/code&gt;), and JSON. They export to eight formats, including CSS custom properties, HTML, PDF, and PNG.&lt;/p&gt;
&lt;p&gt;Turn on iCloud sync and your palettes follow you to all your Macs.&lt;/p&gt;
&lt;h2 id=&quot;a-built-in-contrast-checker&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/introducing-colorcopy/#a-built-in-contrast-checker&quot;&gt;A built-in contrast checker&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Colors rarely live alone. Text sits on a background, an icon sits on a button, and whether that pairing is readable shouldn&#39;t be a guess.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/colorcopy/colorcopy-contrast.jpg&quot; alt=&quot;ColorCopy&#39;s contrast checker, showing WCAG and APCA results for a color pair&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Pick a background and a foreground color and ColorCopy reports the contrast in both WCAG 2, with AA/AAA pass and fail for normal and large text, and APCA, the newer perceptual algorithm. If a pair fails, open the context menu and select fix, and ColorCopy nudges the color just enough to meet the contrast you asked for.&lt;/p&gt;
&lt;p&gt;Color contrast isn&#39;t only an aesthetic decision. For people with low vision, it&#39;s the difference between readable and not.&lt;/p&gt;
&lt;h2 id=&quot;a-bit-of-personality&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/introducing-colorcopy/#a-bit-of-personality&quot;&gt;A bit of personality&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;ColorCopy lives entirely in the menu bar, but it&#39;s not joyless. There are three menu bar icon styles, adjustable swatch sizes, and nine copy sounds to pick from — or silence, if you prefer.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/colorcopy/colorcopy-settings.jpg&quot; alt=&quot;ColorCopy&#39;s settings, showing format, appearance, and sound options&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;privacy&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/introducing-colorcopy/#privacy&quot;&gt;Privacy&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;ColorCopy runs on your Mac. There&#39;s no account, no analytics, no telemetry, no crash reporter, and no server for your data to land on.&lt;/p&gt;
&lt;p&gt;Two things are opt-in. In-app purchase goes through Apple&#39;s StoreKit, and iCloud sync keeps your palettes consistent across your Macs through your own private iCloud account. Sync is off by default, and even when it&#39;s on, your data goes to Apple, never to me.&lt;/p&gt;
&lt;p&gt;It also needs no special permissions. ColorCopy uses Apple&#39;s sandboxed &lt;code&gt;NSColorSampler&lt;/code&gt;, so it never asks for Screen Recording or Accessibility access.&lt;/p&gt;
&lt;h2 id=&quot;pricing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/introducing-colorcopy/#pricing&quot;&gt;Pricing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;ColorCopy is free to download and the free tier includes every feature: all 21 formats, the Color Picker window, the contrast checker, the palette manager, image extraction, favorites, and every customization setting. It&#39;s metered to 50 color copies per month.&lt;/p&gt;
&lt;p&gt;If you want unlimited copies, ColorCopy Pro is a one-time $7.99 purchase that removes the cap. That&#39;s the only difference between the tiers. No subscription.&lt;/p&gt;
&lt;p&gt;You&#39;ll need macOS 14 (Sonoma) or later. It&#39;s available in 10 languages.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;If you copy colors off your screen even occasionally, give &lt;a href=&quot;https://colorcopy.app/&quot;&gt;ColorCopy&lt;/a&gt; a try and let me know what you think!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Introducing TongueType</title>
		<link href="https://www.abeautifulsite.net/posts/introducing-tonguetype/"/>
		<updated>2026-05-14T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/introducing-tonguetype/</id>
		<content type="html">&lt;p&gt;I just launched my first macOS app, &lt;a href=&quot;https://tonguetype.app/&quot;&gt;TongueType&lt;/a&gt;. It&#39;s voice dictation that runs entirely on your Mac. Hold a key, speak, release, and your words appear wherever your cursor happens to be.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/tonguetype/tonguetype-recording.png&quot; alt=&quot;The TongueType recording overlay — a small dark pill with a microphone, waveform, and timer&quot; /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; margin-block: 3rem;&quot;&gt;
  &lt;a href=&quot;https://tonguetype.app/&quot;&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/tonguetype/tonguetype-app-icon.png&quot; alt=&quot;The TongueType app icon&quot; width=&quot;128&quot; height=&quot;128&quot; style=&quot;border-radius: 22.5%;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id=&quot;why-i-made-it&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/introducing-tonguetype/#why-i-made-it&quot;&gt;Why I made it&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I type fast, but I often think faster than I type. When an idea is fully formed in my head, the bottleneck is my fingers.&lt;/p&gt;
&lt;p&gt;macOS has had built-in dictation forever, but I never liked relying on it. Accuracy aside, I didn&#39;t love the idea of my voice taking a trip to a server and back just to write a sentence.&lt;/p&gt;
&lt;p&gt;There are plenty of dictation apps out there. Alas, the good ones tend to want a subscription, a cloud account, or both. I wanted one that stays on my machine and gets out of the way.&lt;/p&gt;
&lt;p&gt;TongueType uses &lt;a href=&quot;https://openai.com/research/whisper&quot;&gt;OpenAI&#39;s Whisper model&lt;/a&gt; running locally on Apple Silicon. Nothing is uploaded, nothing is logged, and there&#39;s no account to create. Your voice never leaves your Mac.&lt;/p&gt;
&lt;h2 id=&quot;how-it-works&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/introducing-tonguetype/#how-it-works&quot;&gt;How it works&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The whole interaction is one key. By default it&#39;s the Right Option key, because it&#39;s sitting right there and your thumb isn&#39;t doing anything important. Hold it, talk, let go. The transcribed text gets inserted at your cursor, whether that&#39;s your editor, your email, a chat box, or a search field.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/tonguetype/tonguetype-settings.jpg&quot; alt=&quot;TongueType&#39;s General settings, showing hotkey and output options&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You can also drop in an audio or video file — WAV, MP3, MP4, MOV — and get a transcript back. Handy for meeting recordings and voice memos.&lt;/p&gt;
&lt;p&gt;A few details I spent longer on than I expected:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A grace period, so a quick accidental tap doesn&#39;t start recording&lt;/li&gt;
&lt;li&gt;Double-tap to latch, for when you want to keep talking without holding the key down&lt;/li&gt;
&lt;li&gt;Cancel phrases, so you can say &amp;quot;scratch that&amp;quot; at the end and discard the whole thing&lt;/li&gt;
&lt;li&gt;Spoken symbols, so &amp;quot;new line&amp;quot; and &amp;quot;question mark&amp;quot; produce the symbol instead of the words&lt;/li&gt;
&lt;li&gt;Post-processing, for the terms that never get dictated properly&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/tonguetype/tonguetype-postprocessing.jpg&quot; alt=&quot;TongueType&#39;s Postprocessing settings, with non-speech filtering, cancel phrases, and spoken-symbol rules&quot; /&gt;&lt;/p&gt;
&lt;p&gt;It speaks twelve languages and detects them automatically.&lt;/p&gt;
&lt;h2 id=&quot;how-i-actually-use-it&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/introducing-tonguetype/#how-i-actually-use-it&quot;&gt;How I actually use it&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Building the app was one thing. Using it every day turned out to be another. A couple months in, it&#39;s worked its way into most of what I do at the keyboard.&lt;/p&gt;
&lt;p&gt;I prompt LLMs with it, which is where it surprised me most. Talking to an AI assistant is conversational by nature, and typing out a long, detailed prompt is tedious. Speaking it isn&#39;t. I get more context into a prompt because I&#39;m not rationing my words to save my fingers.&lt;/p&gt;
&lt;p&gt;I use it for email, too. Replies that used to sit in my drafts get spoken out in a single pass. I still read them before sending, but the blank-page friction is gone. Same for code comments and commit messages, which are really just writing. It&#39;s faster to explain &lt;em&gt;why&lt;/em&gt; a change exists out loud than to stop and type it.&lt;/p&gt;
&lt;p&gt;Every one of those is the same task: the thinking is done, I just have to get the words out.&lt;/p&gt;
&lt;h2 id=&quot;a-bit-of-personality&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/introducing-tonguetype/#a-bit-of-personality&quot;&gt;A bit of personality&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;TongueType lives in the menu bar. The recording overlay is small and out of the way, and you can move it wherever you like on screen. There are twenty accent colors, including Rainbow Mode.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/tonguetype/tonguetype-appearance.jpg&quot; alt=&quot;TongueType&#39;s Appearance settings, with twenty accent colors and overlay options&quot; /&gt;&lt;/p&gt;
&lt;p&gt;None of that was necessary. But it was fun to build.&lt;/p&gt;
&lt;h2 id=&quot;accessibility&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/introducing-tonguetype/#accessibility&quot;&gt;Accessibility&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I want to call this out specifically. &lt;em&gt;Voice dictation isn&#39;t only a convenience.&lt;/em&gt; For some people it&#39;s the difference between using a computer comfortably or not. If typing is painful or difficult for you, TongueType is meant to be a real input method, not an afterthought. That shaped a lot of the decisions above.&lt;/p&gt;
&lt;h2 id=&quot;pricing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/introducing-tonguetype/#pricing&quot;&gt;Pricing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;TongueType is free to try, and the free tier includes every feature. You get 30 minutes of live dictation each month plus short file transcriptions.&lt;/p&gt;
&lt;p&gt;If you want unlimited, TongueType Pro is a one-time $19.99 purchase that covers up to five Macs. No subscription. Buy it once, keep it forever.&lt;/p&gt;
&lt;p&gt;You&#39;ll need macOS 14 or later on an Apple Silicon Mac. Running the model locally is the whole idea, and Apple Silicon is what makes it fast enough to bother.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;If any of this sounds useful, give &lt;a href=&quot;https://tonguetype.app/&quot;&gt;TongueType&lt;/a&gt; a try and let me know what you think!&lt;/p&gt;
&lt;small&gt;
&lt;p&gt;&lt;em&gt;Update: I&#39;ve since released a second macOS app, &lt;a href=&quot;https://colorcopy.app/&quot;&gt;ColorCopy&lt;/a&gt;, a menu bar color picker. If TongueType sounds like your kind of app, that one might too.&lt;/em&gt;&lt;/p&gt;
&lt;/small&gt;
</content>
	</entry>
	
	<entry>
		<title>My Stance on AI in Software Development</title>
		<link href="https://www.abeautifulsite.net/posts/my-stance-on-ai-in-software-development/"/>
		<updated>2026-04-20T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/my-stance-on-ai-in-software-development/</id>
		<content type="html">&lt;p&gt;I believe artificial intelligence is a powerful and valuable tool that can significantly improve how we create, solve problems, and bring ideas to life.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.abeautifulsite.net/posts/my-stance-on-ai-generated-code/&quot;&gt;I didn&#39;t always feel this way.&lt;/a&gt;. But these days, I use AI regularly in my work and I expect that to continue.&lt;/p&gt;
&lt;p&gt;We may not have chosen this reality, but it&#39;s the reality we&#39;re in. The tools and their benefits — costs be damned — can no longer be ignored.&lt;/p&gt;
&lt;p&gt;That said, when people ask &amp;quot;was this made with AI?&amp;quot; the honest answer is rarely simple. AI can speed up many parts of the process, but it doesn’t replace human judgment, creativity, or responsibility. What appears effortless on the surface rests on deliberate human direction, critical thinking, and careful review.&lt;/p&gt;
&lt;p&gt;Getting good results from AI requires active guidance and oversight. The nuances of context, ethics, user needs, and real-world application are simply too varied given the current technology.&lt;/p&gt;
&lt;p&gt;Moreover, AI doesn’t generate meaningful ideas or elegant solutions on its own. Strong human vision, architecture, and decision-making are still essential. There is no prompt, model, or service that can deliver finished, trustworthy work without substantial human input.&lt;/p&gt;
&lt;p&gt;My commitment to you is this: everything I create will be driven by human ideas, architecture, verification, and final review. I will use AI as an assistant to do what I would have done anyway, but more efficiently.&lt;/p&gt;
&lt;p&gt;I will not let AI replace my intelligence, but I &lt;em&gt;will&lt;/em&gt; use it to turn my intelligence into code faster.&lt;/p&gt;
&lt;p&gt;— Cory LaViska&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>How I Use GitHub Issues</title>
		<link href="https://www.abeautifulsite.net/posts/how-i-use-git-hub-issues/"/>
		<updated>2025-08-04T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/how-i-use-git-hub-issues/</id>
		<content type="html">&lt;p&gt;I like using GitHub issues for &lt;em&gt;actionable&lt;/em&gt; things such as bugs and backlog items I&#39;ve committed to doing. Non-maintainers are encouraged to open issues &lt;em&gt;only for bugs&lt;/em&gt;, whereas everything else is a discussion.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bug Report 👉 Issue&lt;/li&gt;
&lt;li&gt;Help/support 👉 Discussion&lt;/li&gt;
&lt;li&gt;Ask a question 👉 Discussion&lt;/li&gt;
&lt;li&gt;Ideas/suggestions 👉 Discussion&lt;/li&gt;
&lt;li&gt;Waxing Philosophical 👉 Discussion&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Alas, no matter how clear you &lt;a href=&quot;https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository&quot;&gt;make your templates&lt;/a&gt;, some folks will inevitably open issues anyway. Fear not! You can use this gem of a feature in GitHub&#39;s sidebar to convert it to a discussion. I use this very liberally. (Tip: make sure you take the time to categorize your discussions. Organization matters!)&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/convert-to-discussion.png&quot; alt=&quot;Screenshot of GitHub&#39;s UI: Convert Issue To Discussion&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Nobody ever got mad that their issue got turned into a discussion.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;strategic-decisions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/how-i-use-git-hub-issues/#strategic-decisions&quot;&gt;Strategic decisions&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Sometimes things need to be addressed but there isn&#39;t anything actionable yet. Perhaps a decision needs to be made. I think it&#39;s best to hash that out in discussions. RFCs, proposals, philosophical discussions are all just that…discussions.&lt;/p&gt;
&lt;p&gt;Once a decision is made, you can create an actionable issue &lt;em&gt;from&lt;/em&gt; the discussion summarizing the problem and the agreed solution, keeping the [often messy] details out of the issue but cleanly linking back to them for reference.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/create-issue-from-discussion.png&quot; alt=&quot;Screenshot of GitHub&#39;s UI: Create Issue From Discussion&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The keyword is &lt;em&gt;actionable&lt;/em&gt;. This can be anything from &amp;quot;implement feature X&amp;quot; to &amp;quot;determine the best approach to Y.&amp;quot; In the case of the latter, the issue should probably contain a follow up, e.g. &amp;quot;once the best approach is determined, implement and document Y&amp;quot;.&lt;/p&gt;
&lt;p&gt;Using this approach combined with &lt;a href=&quot;https://docs.github.com/en/issues/using-labels-and-milestones-to-track-work/about-milestones&quot;&gt;milestones&lt;/a&gt; has been such a joy compared to &lt;em&gt;the old way&lt;/em&gt; of doing issues.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; GitHub issues serve as a clear backlog of committed, actionable TODOs for the project. Meanwhile, the discussion forum flourishes with questions, suggestions, and other thoughts from the community.&lt;/p&gt;
&lt;p&gt;Win-win.&lt;/p&gt;
&lt;hr /&gt;
&lt;small&gt;
&lt;p&gt;nb4 — I&#39;m aware labels exist and I find them more useful as a tool to organize a backlog and triage than to separate actual &amp;quot;issues&amp;quot; from &amp;quot;discussions.&amp;quot; We used to do this before GitHub had discussions, so there&#39;s some history there, but there&#39;s really no need to let non-issues clutter things up anymore.&lt;/p&gt;
&lt;/small&gt;
</content>
	</entry>
	
	<entry>
		<title>Revisiting FOUCE</title>
		<link href="https://www.abeautifulsite.net/posts/revisiting-fouce/"/>
		<updated>2024-12-23T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/revisiting-fouce/</id>
		<content type="html">&lt;p&gt;It&#39;s been awhile since I wrote about &lt;a href=&quot;https://www.abeautifulsite.net/posts/flash-of-undefined-custom-elements&quot;&gt;FOUCE&lt;/a&gt; and I&#39;ve since come up with an improved solution that I think is worth a post.&lt;/p&gt;
&lt;p&gt;This approach is similar to hiding the page content and then fading it in, but I&#39;ve noticed it&#39;s far less distracting without the fade. It also adds a two second timeout to prevent network issues or latency from rendering an &amp;quot;empty&amp;quot; page.&lt;/p&gt;
&lt;p&gt;First, we&#39;ll add a class called &lt;code&gt;reduce-fouce&lt;/code&gt; to the &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; element.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;html&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;reduce-fouce&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  ...
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we&#39;ll add this rule to the CSS.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;
  &lt;span class=&quot;token selector&quot;&gt;html.reduce-fouce&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, we&#39;ll wait until all the custom elements have loaded &lt;em&gt;or&lt;/em&gt; two seconds have elapsed, whichever comes first, and we&#39;ll remove the class causing the content to show immediately.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;module&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;race&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Load all custom elements&lt;/span&gt;
    Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;allSettled&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      customElements&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;whenDefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;my-button&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      customElements&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;whenDefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;my-card&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      customElements&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;whenDefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;my-rating&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Resolve after two seconds&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;resolve&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resolve&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Remove the class, showing the page content&lt;/span&gt;
  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;documentElement&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;classList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;reduce-fouce&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This approach seems to work especially well and won&#39;t end up &amp;quot;stranding&amp;quot; the user if network issues occur.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Web Components Are Not the Future — They’re the Present</title>
		<link href="https://www.abeautifulsite.net/posts/web-components-are-not-the-future-they-re-the-present/"/>
		<updated>2024-09-27T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/web-components-are-not-the-future-they-re-the-present/</id>
		<content type="html">&lt;p&gt;It’s disappointing that some of the most outspoken individuals against Web Components are framework maintainers. These individuals are, after all, in some of the best positions to provide valuable feedback. They have a lot of great ideas!&lt;/p&gt;
&lt;p&gt;Alas, there’s little incentive for them because standards evolve independently and don’t necessarily align with framework opinions. How could they? Opinions are one of the things that make frameworks unique.&lt;/p&gt;
&lt;p&gt;And therein lies the problem. If you’re convinced that &lt;em&gt;your&lt;/em&gt; way is the best and only way, it’s natural to feel disenchanted when a decision is made that you don’t fully agree with.&lt;/p&gt;
&lt;p&gt;This is my open response to &lt;a href=&quot;https://dev.to/ryansolid/web-components-are-not-the-future-48bh&quot;&gt;Ryan Carniato’s post from yesterday&lt;/a&gt; called “Web Components Are Not the Future.”&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;wtf-is-a-component-anyway%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/web-components-are-not-the-future-they-re-the-present/#wtf-is-a-component-anyway%3F&quot;&gt;WTF is a component anyway?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The word &lt;em&gt;component&lt;/em&gt; is a loaded term, but I like to think of it in relation to interoperability. If I write a component in Framework A, I would like to be able to use it in Framework B, C, and D without having to rewrite it or include its entire framework.&lt;/p&gt;
&lt;p&gt;I don’t think many will disagree with that objective.&lt;/p&gt;
&lt;p&gt;We’re not there yet, but the road has been paved and instead of learning to drive on it, frameworks are building…different roads.&lt;/p&gt;
&lt;p&gt;Ryan states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If the sheer number of JavaScript frameworks is any indicator we are nowhere near reaching a consensus on how one should author components on the web. And even if we were a bit closer today we were nowhere near there a decade ago.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The thing is, we don’t need to agree on &lt;em&gt;how&lt;/em&gt; to write components, we just need to agree on the underlying implementation, then you can use classes, hooks, or whatever flavor you want to create them.&lt;/p&gt;
&lt;p&gt;Turns out, we have a very well-known, ubiquitous technology that we’ve chosen to do this with: HTML.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;But it also can have a negative effect. If too many assumptions are made it becomes harder to explore alternative space because everything gravitates around the establishment. What is more established than a web standard that can never change?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If the concern is premature standardization, well, it’s a bit late for that. So let’s figure out how to get from where we are now to where we want to be. The solution isn’t to start over at the specification level, it’s to rethink how front end frameworks engage with current and emerging standards and work to improve them.&lt;/p&gt;
&lt;p&gt;Respectfully, it’s time to stop complaining, move on, and fix the things folks perceive as suboptimal.&lt;/p&gt;
&lt;h2 id=&quot;the-definition-of-component&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/web-components-are-not-the-future-they-re-the-present/#the-definition-of-component&quot;&gt;The definition of component&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;That said, we also need to realize that Web Components aren’t a 1:1 replacement for framework components. They’re tangentially related things, and I think a lot of confusion stems from this. We should really fix the definition of &lt;em&gt;component&lt;/em&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;So the fundamental problem with Web Components is that they are built on Custom Elements. Elements !== Components. More specifically, Elements are a subset of Components. One could argue that every Element could be a Component but not all Components are Elements.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To be fair, I’ve never really liked the term “Web Components” because it competes with the concept of framework components, but that’s what caught on and that&#39;s what most people are familiar with these days.&lt;/p&gt;
&lt;p&gt;Alas, there is a very important distinction here. Sure, a button and a text field can be components, but there are other types. For example, many frameworks support a concept of &lt;em&gt;renderless components&lt;/em&gt; that exist in your code, but not in the final HTML. You can’t do that with Web Components, because every custom element results in an actual DOM element. (FWIW I don’t think this is a bad thing — but I digress…)&lt;/p&gt;
&lt;p&gt;As to why Web components don’t do all the things framework components do, that’s because they’re a lower level implementation of an interoperable &lt;em&gt;element&lt;/em&gt;. They’re not trying to do everything framework components do. That’s what frameworks are for.&lt;/p&gt;
&lt;h2 id=&quot;it%E2%80%99s-ok-to-be-shiny&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/web-components-are-not-the-future-they-re-the-present/#it%E2%80%99s-ok-to-be-shiny&quot;&gt;It’s ok to be shiny&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In fact, this is where frameworks excel. They let you go above and beyond what the platform can do on its own. I fully support this trial-and-error way of doing things.&lt;/p&gt;
&lt;p&gt;After all, it’s fun to explore new ideas and live on the bleeding edge. We got a lot of cool stuff from doing that. We got &lt;code&gt;document.querySelector()&lt;/code&gt; from jQuery. CSS Custom Properties were inspired by Sass. Tagged template literals were inspired by JSX. Soon we’re getting &lt;a href=&quot;https://github.com/tc39/proposal-signals&quot;&gt;signals&lt;/a&gt; from Preact.&lt;/p&gt;
&lt;p&gt;And from all the component-based frameworks that came before them, we got &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_componentsa&quot;&gt;Web Components&lt;/a&gt;: custom HTML elements that can be authored in many different ways (because we know people like choices) and are fully interoperable (if frameworks and metaframeworks would continue to move towards the standard instead of protecting their own).&lt;/p&gt;
&lt;p&gt;Frameworks are a testbed for new ideas that may or may not work out. We all need to be OK with that. Even framework authors. &lt;em&gt;Especially framework authors.&lt;/em&gt; More importantly, we all need to stop being salty when  &lt;em&gt;our way&lt;/em&gt; isn’t what makes it into the browser.&lt;/p&gt;
&lt;p&gt;There will always be a better way to do something, but none of us have the foresight to know what a perfect solution looks like &lt;em&gt;right now&lt;/em&gt;. Hindsight is 20/20. As humans, we’re constantly striving to make things better. We’re really good at it, by the way. But we must have the discipline to reach various checkpoints to pause, reflect, and gather feedback before continuing.&lt;/p&gt;
&lt;p&gt;Even the cheapest cars on the road today will outperform the &lt;a href=&quot;https://en.wikipedia.org/wiki/Ford_Model_T&quot;&gt;Model T&lt;/a&gt; in every way. I’m sure Ford could have made the original Model T way better if they had spent another decade working on it, but do you know what made the next version even better than 10 more years? The feedback they got from actual users who bought them, sat in them, and drove them around on actual roads.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/baby-steps.gif&quot; alt=&quot;Baby steps? Baby steps.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Web Standards offer a promise of stability and we need to move forward to improve them together. Using one’s influence to rally users against the very platform you’ve built your success on is damaging to both the platform and the community.&lt;/p&gt;
&lt;p&gt;We need these incredible minds to be less divisive and more collaborative.&lt;/p&gt;
&lt;h2 id=&quot;the-right-direction&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/web-components-are-not-the-future-they-re-the-present/#the-right-direction&quot;&gt;The right direction&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Imagine if we applied the same arguments against HTML early on. What if we never standardized it at all? Would the Web be a better place if every site required a specific browser? (Narrator: &lt;em&gt;it wasn&#39;t&lt;/em&gt;.) Would it be better if every site was Flash or a Java applet? (Remember Silverlight? lol)&lt;/p&gt;
&lt;p&gt;Sure, there are often better alternatives for every use case, but we have to pick something that works for the majority, then we can iterate on it. Web Components are a huge step in the direction of standardization and we should all be excited about that.&lt;/p&gt;
&lt;p&gt;But the Web Component implementation isn’t compatible with existing frameworks, and therein lies an existential problem.&lt;/p&gt;
&lt;p&gt;Web Components are a threat to the peaceful, proprietary way of life for frameworks that have amassed millions of users — the majority of web developers. Because opinions vary so wildly, when a new standard emerges frameworks can’t often adapt to them without breaking changes. And breaking changes can be detrimental to a user base.&lt;/p&gt;
&lt;p&gt;Have you spotted the issue? You can’t possibly champion Web Standards when you’ve built a non-standard thing that will break if you align with the emerging standard. It’s easier to oppose the threat than to adapt to it.&lt;/p&gt;
&lt;p&gt;And of course Web Components don’t do &lt;em&gt;everything&lt;/em&gt; a framework does. How can the platform possibly add all the features every framework added last week? That would be absolutely reckless.&lt;/p&gt;
&lt;p&gt;And no, the platform doesn’t move as fast as your framework and that’s sometimes painful. But it’s by design. This process is what gives us APIs that continue to work for decades.&lt;/p&gt;
&lt;p&gt;As users, we need to get over this hurdle and start thinking about how frameworks can adapt to current standards and how to evolve them as new ones emerge. Let’s identify shortcomings in the spec and work together to improve the ecosystem instead of arguing about who’s shit smells worse.&lt;/p&gt;
&lt;p&gt;Reinventing the wheel isn’t the answer. Lock-in isn’t the answer.&lt;/p&gt;
&lt;p&gt;This is why I believe that the next generation of frameworks will converge on custom elements as an interoperable component model, enhance that model by sprinkling in awesome features of their own, and focus more on flavors (class-based, functional, signals, etc.) and higher level functionality. As for today&#39;s frameworks? How they adapt will determine how relevant they remain.&lt;/p&gt;
&lt;h2 id=&quot;living-dangerously&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/web-components-are-not-the-future-they-re-the-present/#living-dangerously&quot;&gt;Living dangerously&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Ryan concludes:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;So in a sense there are nothing wrong with Web Components as they are only able to be what they are. It&#39;s the promise that they are something that they aren&#39;t which is so dangerous. The way their existence warps everything around them that puts the whole web at risk. It&#39;s a price everyone has to pay.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So Web Components aren’t the specific vision you had for components. That&#39;s fine. But that&#39;s how it is.&lt;/p&gt;
&lt;p&gt;They&#39;re not Solid components. They’re not React components. They’re not Svelte components. They’re not Vue components. They’re standards-based Web Components that work in all of the above. And they could work &lt;em&gt;even better&lt;/em&gt; in all of the above if all of the above were interested in advancing the platform instead of locking users in.&lt;/p&gt;
&lt;p&gt;I’m not a conspiracy theorist, but I find interesting the number of people who are and have been sponsored and/or hired by for-profit companies whose platforms rely heavily on said frameworks. Do you think it’s in their best interest to follow Web Standards if that means making their service less relevant and less lucrative? Of course not.&lt;/p&gt;
&lt;p&gt;If you’ve built an empire on top of something, there’s absolutely zero incentive to tear it down for the betterment of humanity. That’s not how capitalism works. It’s far more profitable to lock users in and keep them paying. But you know what…?&lt;/p&gt;
&lt;p&gt;Web Standards don&#39;t give a fuck about monetization.&lt;/p&gt;
&lt;h2 id=&quot;longevity-supersedes-ingenuity&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/web-components-are-not-the-future-they-re-the-present/#longevity-supersedes-ingenuity&quot;&gt;Longevity supersedes ingenuity&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The last thing I’d like to talk about is this line here.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Web Components possibly pose the biggest risk to the future of the web that I can see.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Of course, this is from the perspective of a framework author, not from the people actually shipping and maintaining software built using these frameworks. And the people actually shipping software are the majority, but that’s not prestigious so they rarely get the high follower counts.&lt;/p&gt;
&lt;p&gt;The people actually shipping software are tired of framework churn. They&#39;re tired of shit they wrote last month being outdated already. They want stability. They want to know that the stuff they build today will work tomorrow.&lt;/p&gt;
&lt;p&gt;As history has proven, no framework can promise that.&lt;/p&gt;
&lt;p&gt;You know what framework &lt;em&gt;I&lt;/em&gt; want to use? I want a framework that aligns with the platform, not one that replaces it. I want a framework that values incremental innovation over user lock-in. I want a framework that says it&#39;s OK to break things if it means making the Web a better place for everyone. Yes, that comes at a cost, but almost every good investment does, and I would argue that cost will be less expensive than learning a new framework and rebuilding buttons for the umpteenth time.&lt;/p&gt;
&lt;p&gt;The Web platform may not be perfect, but it continuously gets better. I don’t think frameworks are bad but, as a community, we need to recognize that a fundamental piece of the platform has changed and it&#39;s time to embrace the interoperable component model that Web Component APIs have given us…even if that means breaking things to get there.&lt;/p&gt;
&lt;p&gt;The component war is over.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Component Machines</title>
		<link href="https://www.abeautifulsite.net/posts/component-machines/"/>
		<updated>2024-09-05T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/component-machines/</id>
		<content type="html">&lt;p&gt;Components are like little machines. You build them once. Use them whenever you need them.&lt;/p&gt;
&lt;p&gt;Every now and then you open them up to oil them or replace a part, then you send them back to work.&lt;/p&gt;
&lt;p&gt;And work, they do.&lt;/p&gt;
&lt;p&gt;Little component machines just chugging along so you never have to write them from scratch ever again.&lt;/p&gt;
&lt;hr /&gt;
&lt;small&gt;
&lt;p&gt;Adapted from &lt;a href=&quot;https://x.com/claviska/status/1831510899766472969&quot;&gt;this tweet&lt;/a&gt;.&lt;/p&gt;
&lt;/small&gt;
</content>
	</entry>
	
	<entry>
		<title>Styling Custom Elements Without Reflecting Attributes</title>
		<link href="https://www.abeautifulsite.net/posts/styling-custom-elements-without-reflecting-attributes/"/>
		<updated>2024-06-12T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/styling-custom-elements-without-reflecting-attributes/</id>
		<content type="html">&lt;p&gt;I&#39;ve been struggling with the idea of reflecting attributes in custom elements and &lt;a href=&quot;https://www.abeautifulsite.net/posts/reflection-and-custom-states-in-web-components/&quot;&gt;when it&#39;s appropriate&lt;/a&gt;. I think I&#39;ve identified a gap in the platform, but I&#39;m not sure exactly how we should fill it.&lt;/p&gt;
&lt;p&gt;I&#39;ll explain with an example. Let&#39;s say I want to make a simple badge component with primary, secondary, and tertiary variants.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;my-badge&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;variant&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;primary&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;foo&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;my-badge&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;my-badge&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;variant&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;secondary&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;bar&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;my-badge&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;my-badge&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;variant&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;tertiary&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;baz&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;my-badge&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a simple component, but one that demonstrates the problem well. I want to style the badge based on the variant property, but sprouting attributes (which occurs as a result of reflecting a property back to an attribute) is largely considered a bad practice. A lot of web component libraries do it out of necessary to facilitate styling — including &lt;a href=&quot;https://shoelace.style/&quot;&gt;Shoelace&lt;/a&gt; — but is there a better way?&lt;/p&gt;
&lt;h2 id=&quot;the-problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/styling-custom-elements-without-reflecting-attributes/#the-problem&quot;&gt;The problem&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I need to style the badge &lt;em&gt;without&lt;/em&gt; relying on reflected attributes. This means I can&#39;t use &lt;code&gt;:host([variant=&amp;quot;...&amp;quot;])&lt;/code&gt; because the attribute may or may not be set by the user. For example, if the component is rendered in a framework that sets properties instead of attributes, or if the property is set or changed programmatically, the attribute will be out of sync and my styles will be broken.&lt;/p&gt;
&lt;p&gt;So how can I style the badge based its variants without reflection? Let&#39;s assume we have the following internals, which is all we really need for the badge.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;my-badge&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  #shadowRoot
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;slot&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;slot&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;my-badge&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;what-can-we-do-about-it%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/styling-custom-elements-without-reflecting-attributes/#what-can-we-do-about-it%3F&quot;&gt;What can we do about it?&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;I &lt;em&gt;can&#39;t&lt;/em&gt; add classes to the slot, because &lt;code&gt;:host(:has(.slot-class))&lt;/code&gt; won&#39;t match.&lt;/li&gt;
&lt;li&gt;I &lt;em&gt;can&#39;t&lt;/em&gt; set a data attribute on the host element, because that&#39;s the same as reflection and &lt;a href=&quot;https://www.konnorrogers.com/posts/2024/designing-web-components-for-morphing&quot;&gt;might cause issues&lt;/a&gt; with SSR and DOM morphing libraries.&lt;/li&gt;
&lt;li&gt;I &lt;em&gt;could&lt;/em&gt; add a wrapper element around the slot and apply classes to it, but I&#39;d prefer not to bloat the internals with additional elements. With a wrapper, users would have to use &lt;code&gt;::part(wrapper)&lt;/code&gt; to target it. Without the wrapper, they can set background, border, and other CSS properties directly on the host element which is more desirable.&lt;/li&gt;
&lt;li&gt;I &lt;em&gt;could&lt;/em&gt; add &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals/states&quot;&gt;custom states&lt;/a&gt; for each variant, but this gets messy for non-Boolean values and feels like an abuse of the API.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;filling-the-gap&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/styling-custom-elements-without-reflecting-attributes/#filling-the-gap&quot;&gt;Filling the gap&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I&#39;m not sure what the best solution is or could be, but one thing that comes to mind is a way to provide some kind of cross-root version of &lt;code&gt;:has&lt;/code&gt; that works with &lt;code&gt;:host&lt;/code&gt;. Something akin to:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;:host(:has-in-shadow-root(.some-selector))&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* maybe one day… */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you have any thoughts on this one, &lt;a href=&quot;https://x.com/claviska&quot;&gt;hit me up on Twitter&lt;/a&gt;.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Reflection and Custom States in Web Components</title>
		<link href="https://www.abeautifulsite.net/posts/reflection-and-custom-states-in-web-components/"/>
		<updated>2024-06-05T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/reflection-and-custom-states-in-web-components/</id>
		<content type="html">&lt;p&gt;In the Web Component world, &lt;em&gt;attribute reflection&lt;/em&gt; is commonly used to style custom elements both internally and as public APIs for consumers. If you&#39;re not familiar, attribute reflection occurs when an attribute in the DOM is updated due to changes in a corresponding property.&lt;/p&gt;
&lt;p&gt;A lot of folks conflate attributes and properties, so here&#39;s an example.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- This is the open attribute --&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;details&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  ...
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;details&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;
  &lt;span class=&quot;token comment&quot;&gt;// This is the open property. Changing it will &quot;reflect&quot;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// back and update the attribute - but not all attributes&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// reflect!&lt;/span&gt;
  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;details&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;open &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The pattern of using reflection as a styling API likely emerged out of necessity, as the suggested alternative, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CustomStateSet&quot;&gt;Custom States&lt;/a&gt;, only &lt;a href=&quot;https://caniuse.com/mdn-api_elementinternals_states&quot;&gt;recently landed&lt;/a&gt; decent browser support.&lt;/p&gt;
&lt;p&gt;However, from an HTML purist&#39;s perspective, we shouldn&#39;t sprout attributes. It&#39;s largely considered an anti-pattern because attributes are intended to be an input mechanism that should only be set by the consumer.&lt;/p&gt;
&lt;p&gt;This is a sensible argument, but many native elements don&#39;t follow this convention. Here are some examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;id&lt;/code&gt; attribute reflects on all elements&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt; element reflects the &lt;code&gt;open&lt;/code&gt; attribute when expanded&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt; element reflect the &lt;code&gt;open&lt;/code&gt; attribute when shown&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; element reflects the &lt;code&gt;disabled&lt;/code&gt; attribute when disabled&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; element reflects the &lt;code&gt;src&lt;/code&gt; and &lt;code&gt;alt&lt;/code&gt; attributes when set as properties&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; element reflects the &lt;code&gt;src&lt;/code&gt; attribute when set as a property&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; element reflects the &lt;code&gt;type&lt;/code&gt; attribute when set as a property&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;&amp;lt;progress&amp;gt;&lt;/code&gt; element reflects the &lt;code&gt;value&lt;/code&gt; attribute when set as a property&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; element reflects the &lt;code&gt;action&lt;/code&gt; and &lt;code&gt;method&lt;/code&gt; attributes when set as properties&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;&amp;lt;textarea&amp;gt;&lt;/code&gt; component reflects the &lt;code&gt;rows&lt;/code&gt; and &lt;code&gt;cols&lt;/code&gt; attributes when set as properties&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Of course, not all properties reflect. In fact, the rule seems rather arbitrary. For fun, I asked my friendly neighborhood AI — who is more patient and arguably more skilled at deciphering long technical documents then I am — when properties should reflect back to attributes, per the HTML spec.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Reflected properties in HTML are properties that, when changed, update the HTML markup to ensure synchronization between the HTML and the DOM. This allows for changes to be preserved if the page is reloaded or serialized back into a string. The decision to reflect a property is determined by the HTML specification on a case-by-case basis, considering whether the property represents the initial state or current behavior of the element.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It seems there&#39;s not an obvious convention to follow. If we&#39;re reflecting properties back to attributes to represent an element&#39;s &lt;em&gt;initial&lt;/em&gt; state, wouldn&#39;t those attributes already be set by the author of the HTML?&lt;/p&gt;
&lt;p&gt;Besides, some elements reflect their &lt;em&gt;current&lt;/em&gt; state, such as &lt;code&gt;&amp;lt;dialog open&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;details open&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;input checked&amp;gt;&lt;/code&gt;, etc. This suggests it&#39;s OK to reflect attributes to represent state. But if that&#39;s what Custom States intends to solve, why didn&#39;t these native elements use a state, such as &lt;code&gt;:open&lt;/code&gt;?*&lt;/p&gt;
&lt;h2 id=&quot;so-when-should-we-reflect-attributes%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/reflection-and-custom-states-in-web-components/#so-when-should-we-reflect-attributes%3F&quot;&gt;So when &lt;em&gt;should&lt;/em&gt; we reflect attributes?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I usually prefer to align with the platform, but the platform isn&#39;t clear on this one. Because things like this bother me, I&#39;m going to outline some rules I use to determine if an attribute should or shouldn&#39;t reflect.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An attribute should reflect when:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It represents a current state that the user can modify and/or may be interested in observing, such as &lt;code&gt;checked&lt;/code&gt;, &lt;code&gt;disabled&lt;/code&gt;, &lt;code&gt;open&lt;/code&gt;, &lt;code&gt;readonly&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;It represents a value that affects how the component is styled internally or externally. This allows us to target variants** without using an internal wrapper and/or replicating values internally.&lt;/li&gt;
&lt;li&gt;It makes the debugging experience more intuitive for authors and consumers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;An attribute should &lt;em&gt;not&lt;/em&gt; reflect when:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The data type is neither string, number, nor boolean.&lt;/li&gt;
&lt;li&gt;The value is content or otherwise too cumbersome to store in the DOM, e.g. the content of a text area.&lt;/li&gt;
&lt;li&gt;The user is unlikely to have interest in observing the attribute for state or styling purposes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Notes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It&#39;s OK if an attribute reflects &lt;em&gt;and&lt;/em&gt; a custom state is applied. In this case, the consumer can choose how to target it in their own styles.***&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;small&gt;
&lt;p&gt;*There is a non-zero chance that we are stuck in a perpetual hell for the sake of backwards compatibility. Alas, the lack of an obvious pattern makes it hard to identify a best practice moving forward, and user expectation may be contrary based on prior art.&lt;/p&gt;
&lt;p&gt;**I suspect that some folks will disagree with this, so I&#39;ll elaborate. If I have a component that supports multiple variants, e.g. &lt;code&gt;primary&lt;/code&gt;, &lt;code&gt;secondary&lt;/code&gt;, &lt;code&gt;tertiary&lt;/code&gt;, the user will typically set an attribute on the element: &lt;code&gt;&amp;lt;my-badge variant=&amp;quot;primary&amp;quot;&amp;gt;&lt;/code&gt;. But what if they set the corresponding property instead because they&#39;re using a framework that sets properties instead of attributes? This means we can&#39;t rely on &lt;code&gt;:host([variant=&amp;quot;primary&amp;quot;])&lt;/code&gt; in our styles, so we either have to a) map the selected variant to classes somewhere internally, possibly requiring a wrapper element that wouldn&#39;t be needed otherwise; b) use custom states…except we&#39;d need to add one for &lt;em&gt;every&lt;/em&gt; possible variant which isn&#39;t ergonomic for authors or end users; or c) use something like a &lt;code&gt;data-variant&lt;/code&gt; attribute to…shit, this is the same as attribute reflection.&lt;/p&gt;
&lt;p&gt;***Unfortunately, some libraries that use DOM morphing &lt;a href=&quot;https://www.konnorrogers.com/posts/2024/designing-web-components-for-morphing&quot;&gt;might break custom elements&lt;/a&gt; that reflect attributes. As such, it&#39;s a good idea to make sure your default styles don&#39;t rely on them. For example, if the default styles for &lt;code&gt;&amp;lt;your-button variant=&amp;quot;default&amp;quot;&amp;gt;&lt;/code&gt; get lost when you remove the &lt;code&gt;variant&lt;/code&gt; attribute, you&#39;re gonna have a bad time.&lt;/p&gt;
&lt;/small&gt;
</content>
	</entry>
	
	<entry>
		<title>Anchoring Software to Major Versions</title>
		<link href="https://www.abeautifulsite.net/posts/anchoring-software-to-major-versions/"/>
		<updated>2024-05-24T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/anchoring-software-to-major-versions/</id>
		<content type="html">&lt;p&gt;In a &lt;a href=&quot;https://semver.org/&quot;&gt;SemVer&lt;/a&gt; world, major releases are those which contain incompatible API changes. We often see software projects &lt;em&gt;anchor&lt;/em&gt; themselves to major versions for long periods of time, usually with the promise of stability.&lt;/p&gt;
&lt;p&gt;We all know how frustrating it is to upgrade a package and run into tons of breaking changes. Many of us have kept outdated software in production for longer than we should &lt;em&gt;just because&lt;/em&gt; it can be such a pain to update.&lt;/p&gt;
&lt;p&gt;I&#39;ve been thinking a lot about this lately in the context of open source projects*, and I&#39;ve come to believe that anchoring to major versions is counterintuitive. It&#39;s harder for developers, who have to maintain each distinct version for long periods of time; it&#39;s worse for consumers, who eventually get hit with a slew of broken things all at once; and it holds back features and improvements that can&#39;t be implemented &lt;em&gt;until&lt;/em&gt; breaking changes are made.&lt;/p&gt;
&lt;p&gt;Of course, there&#39;s something to be said about maintainer discipline. Are we breaking things for a good reason or just because? Do our changes actually benefit the project and its users, or does it just feel better to do it this way now? Every project is maintained differently.**&lt;/p&gt;
&lt;p&gt;But the more I think about it, the less it makes sense.&lt;/p&gt;
&lt;p&gt;For many projects, major versions should be released more frequently. Things are easier to maintain when the path to upgrading involves less friction; consumers are more apt to retain familiarity with less time in between updates; and developers can stop being scared to do the right thing for fear of a major version bump.&lt;/p&gt;
&lt;p&gt;The right kind of breaking changes are good. We should embrace them rather than avoid them.&lt;/p&gt;
&lt;hr /&gt;
&lt;small&gt;
&lt;p&gt;*I&#39;m aware this logic doesn&#39;t apply as well to consumer-facing products where marketing is tied to major version numbers. &amp;quot;Upgrading from 3.x to 4.x? CLICK HERE TO PURCHASE!&amp;quot; These types of major versions are usually more about new features that were held back for the sake of revenue — you can&#39;t charge for a new release unless it&#39;s a major version! But they otherwise could have been added in a minor release.&lt;/p&gt;
&lt;p&gt;**It&#39;s your project, do whatever you want. But if your goal is to garner trust and grow a community, maybe think twice about haphazardly changing things.&lt;/p&gt;
&lt;/small&gt;
</content>
	</entry>
	
	<entry>
		<title>Building Custom Elements With a Library</title>
		<link href="https://www.abeautifulsite.net/posts/building-custom-elements-with-a-library/"/>
		<updated>2024-03-28T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/building-custom-elements-with-a-library/</id>
		<content type="html">&lt;p&gt;I often get asked why I use &lt;a href=&quot;https://lit.dev/&quot;&gt;Lit&lt;/a&gt; to build web components. Hands down, it&#39;s become my preference after years of working with various libraries and tools. Here&#39;s why I use it.&lt;/p&gt;
&lt;h2 id=&quot;libraries-offer-a-better-dx&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/building-custom-elements-with-a-library/#libraries-offer-a-better-dx&quot;&gt;Libraries offer a better DX&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This seems like a selfish answer for a developer to lean on, but there are advantages to end users as well. A better developer experience (DX) means I can write components and fix bugs faster. In my experience, a lot faster. Lit, for example, maps attributes to properties automatically, meaning I can omit a ton of extra logic from my code.&lt;/p&gt;
&lt;p&gt;Abstractions like this make me more efficient at writing components because I can concentrate on the important stuff. And with less code to worry about, I find components are less prone to bugs. If I had to write those mappings myself, for example, it would get very cumbersome. More code to write, more bytes to load, and more complexity to maintain.&lt;/p&gt;
&lt;h2 id=&quot;keeping-it-dry&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/building-custom-elements-with-a-library/#keeping-it-dry&quot;&gt;Keeping it DRY&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If I were writing vanilla web components, I&#39;d eventually recognize patterns amidst the boilerplate. As any good developer would, I&#39;d split them out and move them into a reusable utility of some sort. That&#39;s the &lt;a href=&quot;https://en.wikipedia.org/wiki/Don%27t_repeat_yourself&quot;&gt;DRY&lt;/a&gt; thing to do, right?&lt;/p&gt;
&lt;p&gt;I&#39;ve been down that road before. &lt;a href=&quot;https://github.com/claviska/sushi-element&quot;&gt;I built my own library&lt;/a&gt; to author web components. Declarative templates, reactive data binding, lifecycle hooks — all the shiny things that make building components fun.&lt;/p&gt;
&lt;p&gt;I ended up spending more time working on the library than the components. If only there were something out there that did exactly what I was looking for…&lt;/p&gt;
&lt;p&gt;Turns out, that was Lit.&lt;/p&gt;
&lt;p&gt;Oddly enough, Lit was about the same size as my own library. What I like about Lit is that it&#39;s designed to work &lt;em&gt;with&lt;/em&gt; the platform, not replace it. Its maintainers are very committed to stability and backwards compatibility, and they have an amazing track record to back this.&lt;/p&gt;
&lt;p&gt;For building a one-off custom element, vanilla APIs will work just fine and save you some bytes. But when you start building a collection of them, the size and maintainability arguments fall apart. In my opinion, it&#39;s wiser to keep those abstractions well-tested, well-documented, and well-separated from the rest of your code.&lt;/p&gt;
&lt;h2 id=&quot;vanilla-apis-are-intentionally-low-level&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/building-custom-elements-with-a-library/#vanilla-apis-are-intentionally-low-level&quot;&gt;Vanilla APIs are intentionally low-level&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The APIs that comprise &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_components&quot;&gt;web components&lt;/a&gt; aren&#39;t like those like you&#39;re used to with React, Vue, et al. Remember, the platform evolves slowly because it has to commit to features for many, many years. This is why webpages from decades ago still work in modern browsers.&lt;/p&gt;
&lt;p&gt;Web component APIs took a long time to establish. They were designed to be low-level so developers can build on top of them. As a result, vanilla web components tend to have a lot of boilerplate.&lt;/p&gt;
&lt;p&gt;You know how you can build React components without JSX?&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// without JSX&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createElement &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Greeting&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;h1&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;greeting&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;Hello &#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;i&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;. Welcome!&#39;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sure, it&#39;s possible, but isn&#39;t this much easier to work with?&lt;/p&gt;
&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// with JSX&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Greeting&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;greeting&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
      Hello &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;. Welcome!
    &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Extrapolate this concept to more complex components. Which would you rather build and maintain? In some ways, Lit is to web components what JSX is to React. You &lt;em&gt;can&lt;/em&gt; build things without it, but I wouldn&#39;t recommend it.&lt;/p&gt;
&lt;p&gt;At the end of the day, the way a web component is built is an implementation detail. I can swap out Lit for any other library and, as long as I don&#39;t change the public API of my components, most users would never notice.&lt;/p&gt;
&lt;p&gt;They&#39;re just HTML elements, after all.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Design Systems Are An Investment</title>
		<link href="https://www.abeautifulsite.net/posts/design-systems-are-an-investment/"/>
		<updated>2023-11-28T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/design-systems-are-an-investment/</id>
		<content type="html">&lt;p&gt;It&#39;s hard to put a value on a design system. It&#39;s a lot easier to add up the costs of said design system, especially in terms of salaries and development time. It&#39;s even easier to target a design system as the thing that&#39;s holding up a product from getting delivered.&lt;/p&gt;
&lt;p&gt;The truth is, design systems aren&#39;t made to slow you down or piss you off, they&#39;re made to make you more productive. What a lot of organizations fail to understand is that the initial investment pays dividends later on. Well-designed components, patterns, and guidelines take time. But they always result in better products.&lt;/p&gt;
&lt;p&gt;Your design system shouldn&#39;t be a target. It should be a beacon.&lt;/p&gt;
&lt;p&gt;But design system teams are usually siloed. They tend to live higher up in the org chart because they make decisions that affect every product underneath them. They&#39;re often so segmented from the rest of the organization that they become barriers to their own users.&lt;/p&gt;
&lt;p&gt;I used to think that design system teams were special and that they &lt;em&gt;needed&lt;/em&gt; to live up there, but I don&#39;t think that&#39;s necessarily true anymore. Yes, you need support from management, but you can&#39;t rule from the top down with an iron fist. It must be a team effort. Respect has to be mutual for everything to work.&lt;/p&gt;
&lt;p&gt;Break down the barricades, the fences, and the walls. Make your design system team accessible to their consumers. Fund them properly so they have the resources to meet the objectives you&#39;ve set for them. Educate consumers so they understand the benefits, the expectations, and the workflows that will make collaboration with your design system team a success.&lt;/p&gt;
&lt;p&gt;I know it&#39;s easy to blame the design system for holding things up. Everyone loves a scapegoat. But don&#39;t let today&#39;s needs interfere with tomorrow&#39;s progress. Understand what it means to invest. Understand the importance of working together to break out of impasses.&lt;/p&gt;
&lt;p&gt;And design system teams — offer some grace to your users. Your job is to create guidelines, not to enforce them religiously. When consumers color outside the lines, your first instinct shouldn&#39;t be to strike them down, but to understand &lt;em&gt;why&lt;/em&gt; and facilitate their needs in a way that benefits everyone moving forward.&lt;/p&gt;
&lt;p&gt;No, you won&#39;t see an immediate payoff from any of this. But anyone who&#39;s played this game long enough knows that a quick win today isn&#39;t nearly as a good as an investment that pays dividends for years to come.&lt;/p&gt;
&lt;p&gt;If it&#39;s unclear what that means, investing in your design system &lt;em&gt;now&lt;/em&gt; will mean more consistency, more productivity, improved code quality, less bugs, less maintenance burdens, and happier teams.&lt;/p&gt;
&lt;p&gt;In the words of &lt;a href=&quot;https://en.wikipedia.org/wiki/Peter_Lynch&quot;&gt;Peter Lynch&lt;/a&gt;: &lt;em&gt;&amp;quot;Know what you own, and why you own it.&amp;quot;&lt;/em&gt;&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>How to File a Bug Report</title>
		<link href="https://www.abeautifulsite.net/posts/how-to-file-a-bug-report/"/>
		<updated>2023-11-21T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/how-to-file-a-bug-report/</id>
		<content type="html">&lt;p&gt;They say there&#39;s no such thing as bug-free code. When problems arise, creating a &lt;a href=&quot;https://en.wikipedia.org/wiki/Minimal_reproducible_example&quot;&gt;minimal reproduction&lt;/a&gt; will give you the best chance of a speedy resolution.&lt;/p&gt;
&lt;p&gt;When a potential bug is discovered, many developers&#39; first reaction is to file an issue. That&#39;s great, but please exercise due diligence before posting! Have you reviewed the docs to confirm the behavior in question? Are you able to reproduce the bug &lt;em&gt;outside&lt;/em&gt; of your app? Have you removed all unrelated code to make sure nothing else is causing the problem?&lt;/p&gt;
&lt;p&gt;I get it — creating a reproduction takes time! Why should that be on you if the bug is upstream? The thing is, the process of creating a minimal reproduction will often uncover the problem and, in many cases, the problem will be in your own code. I know that sounds arrogant but, as an open source maintainer, I see it happen quite frequently.&lt;/p&gt;
&lt;h2 id=&quot;help-us-help-you&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/how-to-file-a-bug-report/#help-us-help-you&quot;&gt;Help Us Help You&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;That&#39;s not to say our libraries don&#39;t have bugs…they totally do! We&#39;re just asking you to help diagnose the problem before we spend hours diving into &lt;em&gt;your code&lt;/em&gt; only to realize it&#39;s not something we can fix in &lt;em&gt;our code&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;If you&#39;re using our software, we&#39;ve already provided some kind of value to you. It&#39;s not fair to ask us to troubleshoot your app. Maintainers generally &lt;em&gt;want&lt;/em&gt; to eliminate bugs from their software, but triaging issues can be a painstaking task, especially in larger projects.&lt;/p&gt;
&lt;p&gt;Even if your bug report is completely valid, an issue that lacks sufficient information — or has too much of the &lt;em&gt;wrong&lt;/em&gt; information — can easily fly under the radar for many reasons.&lt;/p&gt;
&lt;p&gt;Think of it from a maintainer&#39;s perspective. You wake up in the morning to three new bug reports:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Bug #1&lt;/strong&gt; – doesn&#39;t have enough information, just a screenshot of the suspected problem and a line of text that vaguely describes it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bug #2&lt;/strong&gt; – has multiple screenshots of CI output and VS Code windows, but nothing else.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bug #3&lt;/strong&gt; – has a clear description of the problem and a minimal reproduction. The submitter has thoughtfully included all relevant information pertaining to the issue.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Which one would &lt;em&gt;you&lt;/em&gt; be most willing to resolve first?&lt;/p&gt;
&lt;h2 id=&quot;better-bug-reports&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/how-to-file-a-bug-report/#better-bug-reports&quot;&gt;Better Bug Reports&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here are some tips to help you get results faster. Investing a bit of time up front will usually lead to a more positive result. After all, there&#39;s nothing worse than watching your issue collect dust.*&lt;/p&gt;
&lt;h3 id=&quot;do&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/how-to-file-a-bug-report/#do&quot;&gt;Do&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Be courteous and responsive&lt;/li&gt;
&lt;li&gt;Search for existing issues&lt;/li&gt;
&lt;li&gt;Provide all the information necessary to reproduce the problem&lt;/li&gt;
&lt;li&gt;Provide a minimal reproduction when it makes sense&lt;/li&gt;
&lt;li&gt;Taper your expectations — many maintainers do this for free!&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;don&#39;t&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/how-to-file-a-bug-report/#don&#39;t&quot;&gt;Don&#39;t&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Include information that doesn&#39;t pertain to the bug&lt;/li&gt;
&lt;li&gt;Include multiple bug reports in the same issue&lt;/li&gt;
&lt;li&gt;Be rude to maintainers or anyone else involved&lt;/li&gt;
&lt;li&gt;Spam the maintainers with follow ups&lt;/li&gt;
&lt;li&gt;Point fingers or blame others — it&#39;s just not productive&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;just-for-fun&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/how-to-file-a-bug-report/#just-for-fun&quot;&gt;Just for Fun&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In case you were wondering, here&#39;s how maintainers tend to feel when various bug reports are filed. 🤣&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/bug-reports.png&quot; alt=&quot;Bug Reports chart&quot; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;small&gt;
&lt;p&gt;*Unfortunately, some maintainers &lt;em&gt;are&lt;/em&gt; simply unresponsive. In my experience, the majority of open source authors care about their projects and want to be good stewards. Sometimes it can help to offer a bounty or, better yet, a PR. Alas, I&#39;ve seen really good PRs collect dust too. In that case, you might need to consider forking the project or finding an alternative.&lt;/p&gt;
&lt;/small&gt;
</content>
	</entry>
	
	<entry>
		<title>Thoughts on Framework Churn</title>
		<link href="https://www.abeautifulsite.net/posts/thoughts-on-framework-churn/"/>
		<updated>2023-11-16T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/thoughts-on-framework-churn/</id>
		<content type="html">&lt;p&gt;I often worry about framework churn. A lot. But using a framework isn&#39;t a bad thing. After all, they save time. They help you build things faster.&lt;/p&gt;
&lt;p&gt;Yes, there are costs associated with frameworks &lt;em&gt;later on&lt;/em&gt;, especially as new versions come out and your app instantly feels like legacy software. It can be exhausting trying to keep up, especially when your work schedule doesn&#39;t account for that type of maintenance.&lt;/p&gt;
&lt;p&gt;While the upfront savings of using a framework offsets much of the eventual cost of its churn, there might be ways to reduce it even more.&lt;/p&gt;
&lt;h2 id=&quot;a-tale-of-churn&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/thoughts-on-framework-churn/#a-tale-of-churn&quot;&gt;A Tale of Churn&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Over the years, I&#39;ve become somewhat averse to frameworks because I&#39;ve had bad experiences with churn. One time, I wrote an app using Vue 2 and, less than a year later, Vue 3 shipped. I went to upgrade and realized that &lt;a href=&quot;https://element.eleme.io/&quot;&gt;Element&lt;/a&gt;, the Vue-based component library I was using, didn&#39;t support Vue 3! I was stuck, unless of course I wanted to swap out every single UI component in the app.&lt;/p&gt;
&lt;p&gt;Eventually, &lt;a href=&quot;https://element-plus.org/en-US/&quot;&gt;Element released a version for Vue 3&lt;/a&gt;, but then I had to deal with breaking changes from both the framework &lt;em&gt;and&lt;/em&gt; the component library. It felt like absolute chaos and I never want to deal with that again.*&lt;/p&gt;
&lt;p&gt;It&#39;s easy to say &amp;quot;fuck frameworks&amp;quot; out of frustration, but that&#39;s not a realistic option. Modern apps expect too much to write everything from scratch. Yes, the Web platform is getting more and more amazing features, but many APIs are intentionally lower level. Frameworks smooth out those rough edges and tend to provide better &lt;abbr title=&quot;Developer Experience&quot;&gt;DX&lt;/abbr&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-age-of-metaframeworks&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/thoughts-on-framework-churn/#the-age-of-metaframeworks&quot;&gt;The Age of Metaframeworks&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As React, Vue, et al continue to evolve, we&#39;re seeing more and more metaframeworks pop up. It&#39;s almost as though you can&#39;t be successful as a framework &lt;em&gt;without&lt;/em&gt; having a metaframework. React has &lt;a href=&quot;https://nextjs.org/&quot;&gt;Next.js&lt;/a&gt; and &lt;a href=&quot;https://remix.run/&quot;&gt;Remix&lt;/a&gt;. Vue has &lt;a href=&quot;https://nuxt.com/&quot;&gt;Nuxt.js&lt;/a&gt;. Angular has &lt;a href=&quot;https://analogjs.org/&quot;&gt;Analog&lt;/a&gt;. Svelte has &lt;a href=&quot;https://kit.svelte.dev/&quot;&gt;SvelteKit&lt;/a&gt;. Solid.js has &lt;a href=&quot;https://start.solidjs.com/&quot;&gt;SolidStart&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This seems like complete madness to me. We&#39;re building abstractions on top of abstractions, further locking users into those ecosystems and making churn more of a problem than ever.&lt;/p&gt;
&lt;p&gt;Sure, the box looks nice and shiny on the outside but, once you take the shrinkwrap off, there&#39;s a lot of stuff inside that won&#39;t age well. Many developers don&#39;t realize this until it&#39;s too late. Or maybe they just don&#39;t care.&lt;/p&gt;
&lt;p&gt;In this industry, you don&#39;t win by building well-architected apps. You win by shipping fast and moving on. It will be someone else&#39;s problem soon, so fuck it. We used to joke about the Web being the wild west of the programming world, but it really is.&lt;/p&gt;
&lt;h2 id=&quot;tread-lightly&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/thoughts-on-framework-churn/#tread-lightly&quot;&gt;Tread Lightly&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I&#39;ve been thinking about this for a long time and I believe the compromise is to use whatever framework you like, but don&#39;t go all in on it. Consider avoiding metaframeworks. Avoid component libraries that aren&#39;t interoperable. (This is one place web component libraries such as &lt;a href=&quot;https://shoelace.style/&quot;&gt;Shoelace&lt;/a&gt; shine, because they work everywhere and won&#39;t break as frameworks evolve.) Avoid building every possible piece of your app in a framework-specific way and try to make the important chunks more portable.&lt;/p&gt;
&lt;p&gt;Each framework is different and it&#39;s probably impossible to codify this advice, so I&#39;m not going to attempt to. What I will say is, as you develop your app, consider the effort it would take to swap out your current framework for another. Would it be trivial or would it require a complete rewrite? Which pieces will be reusable and which pieces will need to be redeveloped?&lt;/p&gt;
&lt;p&gt;Frameworks save you a lot of time up front, so consider using some of that time to architect your application more thoughtfully. Allow your app&#39;s concerns to be separated in such a way that the important pieces of it are more portable than if you were to write it in and for the framework.&lt;/p&gt;
&lt;p&gt;I care about my craft. I care about the quality and maintainability of the things I create. Sometimes that means choosing the hard right over the easy wrong. While some level of framework churn is inevitable, a well-designed application can alleviate a lot of that pain later on.&lt;/p&gt;
&lt;hr /&gt;
&lt;small&gt;
&lt;p&gt;*&lt;em&gt;&amp;quot;But Cory, you wouldn&#39;t have that problem if you used React!&amp;quot;&lt;/em&gt; React has its own problems. It started with class-based components, then the world switched to hooks and class components were suddenly shit and if you used them you were a second-class developer. Now React Server Components are the hot new thing and everyone&#39;s pivoting towards that shiny thing. React may not seem to churn as much, but its paradigms certainly do.&lt;/p&gt;
&lt;/small&gt;
</content>
	</entry>
	
	<entry>
		<title>Better Buttons with color-mix() and Custom Properties</title>
		<link href="https://www.abeautifulsite.net/posts/better-buttons-with-color-mix-and-custom-properties/"/>
		<updated>2023-08-23T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/better-buttons-with-color-mix-and-custom-properties/</id>
		<content type="html">&lt;p&gt;Let&#39;s build a button that accepts one color and calculates its hover and focus states automatically. For this experiment, we&#39;ll use &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties&quot;&gt;CSS Custom Properties&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color-mix&quot;&gt;color-mix()&lt;/a&gt;, and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/oklch&quot;&gt;OKLCH&lt;/a&gt; to ensure that tints and shades are perceptually uniform.&lt;/p&gt;
&lt;p&gt;To keep things simple, we&#39;ll follow today&#39;s flat design trend and use a single color for the background. We&#39;ll store that color in a custom property so we can reuse it and change things up as we go.&lt;/p&gt;
&lt;p&gt;Let&#39;s kick things off with some styles.&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* Set some defaults for the button */&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;:root&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;--button-bg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; slategrey&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/* Remove factory button styles and add our own */&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;unset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; all&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;font&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 16px sans-serif&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 6px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--button-bg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; white&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; .875rem 1.125rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;cursor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; pointer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;transition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100ms background-color&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/* Tint the background when hovering */&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;button:hover&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;color-mix&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;in oklch&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--button-bg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; white 8%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/* Shade the background when clicked */&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;button:active&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;color-mix&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;in oklch&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--button-bg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; black 4%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/* Remove the default focus ring */&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;button:focus&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;outline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/* Provide a color-matched focus ring for keyboard users */&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;button:focus-visible&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;outline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; solid 3px &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--button-bg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;outline-offset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&#39;re using a custom property called &lt;code&gt;--button-bg&lt;/code&gt; that sets the button&#39;s background. Using a custom property allows us to pass it into the &lt;code&gt;color-mix()&lt;/code&gt; function to calculate the hover and active states. This also allows us to use it again to make a color-matched outline for the focus state.&lt;/p&gt;
&lt;p&gt;The magic is here:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* Tint the background when hovering */&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;button:hover&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;color-mix&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;in oklch&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--button-bg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; white 8%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/* Shade the background when clicked */&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;button:active&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;color-mix&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;in oklch&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--button-bg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; black 4%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using &lt;code&gt;color-mix()&lt;/code&gt;, we can adjust the tint/shade based on the background color, meaning we don&#39;t need to manually select lighter/darker colors for those states. And because we&#39;re using OKLCH, the variations will be perceptually uniform, &lt;a href=&quot;https://lea.verou.me/blog/2020/04/lch-colors-in-css-what-why-and-how/#3.-lch-lightness-actually-means-something&quot;&gt;unlike HSL&lt;/a&gt;. This means that tints and shades will look consistent for any color we choose!&lt;/p&gt;
&lt;p&gt;Oh, and because we&#39;re using a custom property, we can easily test that theory by setting &lt;code&gt;--button-bg&lt;/code&gt; to any color. Note how the hover and focus states update accordingly in this example.*&lt;/p&gt;
&lt;iframe height=&quot;360&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;Color mix with buttons&quot; src=&quot;https://codepen.io/claviska/embed/RwEbXeW?default-tab=result&quot; frameborder=&quot;no&quot; loading=&quot;lazy&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;
  See the Pen &lt;a href=&quot;https://codepen.io/claviska/pen/RwEbXeW&quot;&gt;
  Color mix with buttons&lt;/a&gt; by Cory LaViska (&lt;a href=&quot;https://codepen.io/claviska&quot;&gt;@claviska&lt;/a&gt;)
  on &lt;a href=&quot;https://codepen.io/&quot;&gt;CodePen&lt;/a&gt;.
&lt;/iframe&gt;
&lt;p&gt;The caveat is &lt;a href=&quot;https://caniuse.com/?search=color-mix&quot;&gt;browser support for &lt;code&gt;color-mix()&lt;/code&gt;&lt;/a&gt;, which is green across the board, but still somewhat recent. However, I would argue that this is a great candidate for &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Progressive_Enhancement&quot;&gt;progressive enhancement&lt;/a&gt;, as the absence of color changes on hover and click doesn&#39;t affect the function of the button.&lt;/p&gt;
&lt;p&gt;Not bad for a few lines of CSS!&lt;/p&gt;
&lt;hr /&gt;
&lt;small&gt;
&lt;p&gt;*Alas, we can&#39;t automatically ensure the label&#39;s contrast based on the background color, but when &lt;a href=&quot;https://www.w3.org/TR/css-color-5/&quot;&gt;CSS Color Module Level 5&lt;/a&gt; lands, we&#39;ll get &lt;a href=&quot;https://caniuse.com/css-relative-colors#:~:text=The%20CSS%20Relative%20Color%20syntax,any%20of%20the%20color%20values.&quot;&gt;relative colors&lt;/a&gt; that will &lt;a href=&quot;https://twitter.com/anatudor/status/1693855796499468720&quot;&gt;allow us to do just that&lt;/a&gt;!&lt;/p&gt;
&lt;/small&gt;
</content>
	</entry>
	
	<entry>
		<title>Dynamic Slots</title>
		<link href="https://www.abeautifulsite.net/posts/dynamic-slots/"/>
		<updated>2023-07-19T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/dynamic-slots/</id>
		<content type="html">&lt;p&gt;Web Component authors already know how powerful &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/slot&quot;&gt;slots&lt;/a&gt; are, but what if you could do even more with them? Here&#39;s an interesting technique to use (or abuse) slots in your custom elements. I&#39;ve been calling the pattern &lt;em&gt;dynamic slots&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Before we dive in, let&#39;s take a quick look at how slots actually work. Here&#39;s a custom button with a label and an image.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;my-button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  Click me
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;slot&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;icon&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;my-button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And let&#39;s imagine this is the button&#39;s template, which will be rendered in a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot&quot;&gt;shadow root&lt;/a&gt;.*&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  #shadow-root
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;icon&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;slot&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;icon&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;slot&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;

      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;label&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;slot&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;slot&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you&#39;re wondering why one slot has a name and the other doesn&#39;t, that&#39;s because there are two types of slots! By default, all content goes into the aptly named &lt;em&gt;default slot&lt;/em&gt; — the one without a &lt;code&gt;name&lt;/code&gt; attribute.&lt;/p&gt;
&lt;p&gt;Elements with a &lt;code&gt;slot&lt;/code&gt; attribute, however, will go inside of the corresponding &lt;em&gt;named slot&lt;/em&gt;. A named slot is simply a slot with a &lt;code&gt;name&lt;/code&gt; attribute. In this case, the &lt;code&gt;&amp;lt;img slot=&amp;quot;icon&amp;quot;&amp;gt;&lt;/code&gt; will be &amp;quot;slotted&amp;quot; into the named slot &lt;code&gt;&amp;lt;slot name=&amp;quot;icon&amp;quot;&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you&#39;re feeling comfortable with everything up to this point, you&#39;re ready to move onto the next section. Otherwise, I&#39;d suggest reading more about &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_templates_and_slots&quot;&gt;templates and slots&lt;/a&gt; before continuing.&lt;/p&gt;
&lt;h2 id=&quot;making-things-dynamic&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/dynamic-slots/#making-things-dynamic&quot;&gt;Making Things Dynamic&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Since slots can be named arbitrarily, we have a lot of flexibility here. And since there&#39;s no limit as to how many can exist in a shadow root, we can do some pretty interesting things. Here&#39;s another contrived example. This time, we&#39;ll build a custom element grid that accepts an [oversimplified] attribute of columns and rows.&lt;/p&gt;
&lt;p&gt;Under the hood, the grid will render a &lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt; based on the provided attributes. For brevity, we&#39;ll use &lt;a href=&quot;https://lit.dev/&quot;&gt;Lit&lt;/a&gt; to build it and the markup to use it will look like this.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;my-grid&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;cols&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;a,b,c,d,e&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rows&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1,2,3,4,5&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;my-grid&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Inside the custom element, our render function will look something like this.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cols &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cols&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;,&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; rows &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rows&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;,&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
    &amp;lt;table&gt;
      &amp;lt;thead&gt;
        &amp;lt;tr&gt;
          &amp;lt;th&gt;&amp;lt;/th&gt;
          &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;cols&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;col&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;th&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;col&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/th&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
        &amp;lt;/tr&gt;
      &amp;lt;/thead&gt;
      &amp;lt;tbody&gt;
        &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;rows&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
          &amp;lt;tr&gt;
            &amp;lt;th&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;row&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/th&gt;
            &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;cols&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;col&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
              &amp;lt;td&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;col &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; row&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/td&gt;
            &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
          &amp;lt;/tr&gt;
        &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
      &amp;lt;/tbody&gt;
    &amp;lt;/table&gt;
  &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;iframe height=&quot;600&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;Web Components: dynamic slots in a custom grid (part 2)&quot; src=&quot;https://codepen.io/claviska/embed/VwVdXWo?default-tab=result&quot; frameborder=&quot;no&quot; loading=&quot;lazy&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;
  See the Pen &lt;a href=&quot;https://codepen.io/claviska/pen/VwVdXWo&quot;&gt;
  Web Components: dynamic slots in a custom grid (part 2)&lt;/a&gt; by Cory LaViska (&lt;a href=&quot;https://codepen.io/claviska&quot;&gt;@claviska&lt;/a&gt;)
  on &lt;a href=&quot;https://codepen.io/&quot;&gt;CodePen&lt;/a&gt;.
&lt;/iframe&gt;
&lt;p&gt;Notice how the user isn&#39;t slotting in each cell &lt;em&gt;declaratively&lt;/em&gt;. Instead, they&#39;re generated &lt;em&gt;imperatively&lt;/em&gt; based on the columns and rows provided to the element.**&lt;/p&gt;
&lt;p&gt;Given this API, how can we let users slot in custom content for specific cells? In a real data grid, we&#39;d probably pass an array of objects like this to populate the grid.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;grid&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rows &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1234&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Content from data store&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We &lt;em&gt;could&lt;/em&gt; ask users to loop through the data and modify content as needed, but that seems sloppy. It would be better to offer a declarative API, so let&#39;s modify our example to make use of dynamic slots!&lt;/p&gt;
&lt;p&gt;We&#39;ll start by wrapping each cell with a named slot using the &lt;code&gt;cell:{col}{row}&lt;/code&gt; convention, so a slot named &lt;code&gt;cell:a1&lt;/code&gt; will target the first row in the first column of the grid. The custom element&#39;s template will look like this now.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cols &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cols&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;,&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; rows &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rows&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;,&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
    &amp;lt;table&gt;
      &amp;lt;thead&gt;
        &amp;lt;tr&gt;
          &amp;lt;th&gt;&amp;lt;/th&gt;
          &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;cols&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;col&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;th&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;col&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/th&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
        &amp;lt;/tr&gt;
      &amp;lt;/thead&gt;
      &amp;lt;tbody&gt;
        &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;rows&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
          &amp;lt;tr&gt;
            &amp;lt;th&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;row&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/th&gt;
            &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;cols&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;col&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
              &amp;lt;td&gt;&amp;lt;slot name=&quot;cell:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;col &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; row&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;col &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; row&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/slot&gt;&amp;lt;/td&gt;
            &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
          &amp;lt;/tr&gt;
        &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
      &amp;lt;/tbody&gt;
    &amp;lt;/table&gt;
  &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The magic behind dynamic slots exists right here.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;slot&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cell:${col + row}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This results in a slot for every single cell that we can target in our HTML! Thus, the new markup will look like this.***&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;my-grid&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;cols&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;a,b,c,d,e&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rows&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1,2,3,4,5&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- you can slot in as many or as few cells as you like --&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;slot&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cell:b3&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;foo&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;slot&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cell:d4&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;bar&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;slot&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cell:e2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;baz&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;my-grid&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;iframe height=&quot;600&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;Web Components: dynamic slots in a custom table&quot; src=&quot;https://codepen.io/claviska/embed/zYMaWGj?default-tab=result&quot; frameborder=&quot;no&quot; loading=&quot;lazy&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;
  See the Pen &lt;a href=&quot;https://codepen.io/claviska/pen/zYMaWGj&quot;&gt;
  Web Components: dynamic slots in a custom table&lt;/a&gt; by Cory LaViska (&lt;a href=&quot;https://codepen.io/claviska&quot;&gt;@claviska&lt;/a&gt;)
  on &lt;a href=&quot;https://codepen.io/&quot;&gt;CodePen&lt;/a&gt;.
&lt;/iframe&gt;
&lt;p&gt;In this example, we used dynamic slots to let users customize the content of each cell. Remember that you can move the slot around, though! Perhaps you only want users to append content instead of replacing it entirely. In that case, you&#39;d render the cell&#39;s content and then follow it with a dynamic slot. Or maybe you only want certain columns to be customizable, in which case you&#39;d only render the slot in cells within those columns.&lt;/p&gt;
&lt;p&gt;Perhaps a more realistic example is a date picker you want to add date-specific labels or icons to. The use cases tend to be quite specific, but dynamic slots can be really useful when you&#39;re iterating data and want to sprinkle in declarative customizations in a way regular slots just can&#39;t.&lt;/p&gt;
&lt;p&gt;Anyways, that&#39;s the gist of dynamic slots!&lt;/p&gt;
&lt;h2 id=&quot;suggested-naming-convention&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/dynamic-slots/#suggested-naming-convention&quot;&gt;Suggested Naming Convention&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you choose to follow this pattern, I&#39;d suggest using a colon to delimit the slot&#39;s primary name and it&#39;s positional name.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;slot&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;item:1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;slot&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;slot&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;item:2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;slot&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;slot&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;item:3&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;slot&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This feels cleaner than &lt;code&gt;item-n&lt;/code&gt; and makes it a bit easier to document, especially if you use other dashes in slot names. Of course, this is by no means a requirement!&lt;/p&gt;
&lt;h2 id=&quot;caveats&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/dynamic-slots/#caveats&quot;&gt;Caveats&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&amp;quot;Just because you can, doesn&#39;t mean you should&amp;quot; applies here. Here are some reasons you might want to avoid this pattern.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dynamic slots, like most declarative things, result in more HTML. Use them sensibly to avoid long load times.&lt;/li&gt;
&lt;li&gt;More slots means more DOM footprint, so you might run into performance issues if you get too crazy with it.&lt;/li&gt;
&lt;li&gt;Some folks might consider this an anti-pattern. I understand that perspective, but there seem to be use cases where dynamic slots make a lot of sense.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;small&gt;
&lt;p&gt;*The button example is a bit contrived, but try to imagine a more complex component. The spans aren&#39;t strictly necessary, but they help demonstrate the fact that slots can be rendered anywhere in a template.&lt;/p&gt;
&lt;p&gt;**This is a common pattern for data grids and other components that render large amounts of data from a data store. Component authors &lt;em&gt;could&lt;/em&gt; offer a declarative API that lets consumers slot in columns and rows, but this usually requires more effort from the author and the end user because authors need to do the work to watch/parse the slotted content and end users need to massage raw data into a custom, table-like API. It&#39;s not fun for anyone.&lt;/p&gt;
&lt;p&gt;***In a real world application, you probably wouldn&#39;t use &lt;em&gt;col:row&lt;/em&gt; for naming dynamic slots. An id is a much better way to link database records to slots.&lt;br /&gt;
&lt;/p&gt;&lt;/small&gt;&lt;p&gt;&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>My Commitment to Accessibility</title>
		<link href="https://www.abeautifulsite.net/posts/my-commitment-to-accessibility/"/>
		<updated>2023-06-02T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/my-commitment-to-accessibility/</id>
		<content type="html">&lt;p&gt;I recognize the need for all users, regardless of ability or device, to have undeterred access to the websites and applications that are created with my software. This is an important goal of my projects.&lt;/p&gt;
&lt;p&gt;Oftentimes, people will ask &amp;quot;is it accessible?&amp;quot; I&#39;m reluctant to answer because accessibility isn&#39;t binary — there&#39;s no simple &amp;quot;yes&amp;quot; or &amp;quot;no&amp;quot; response to provide. What seems accessible to a sighted user might be completely inaccessible to a non-sighted user. And even if you optimize for various screen readers, you still have to account for low-level vision, color blindness, hearing impairments, mobility impairments, and more.&lt;/p&gt;
&lt;p&gt;Accessibility is something you have to continuously strive for. No individual contributor — or perhaps even an entire team — can claim their software is 100% accessible because of the sheer diversity of abilities, devices, assistive technologies, and individual use cases.&lt;/p&gt;
&lt;p&gt;Furthermore, accessibility doesn&#39;t stop at the component level. Using accessible building blocks doesn&#39;t magically make the rest of your webpage or application compliant. There is no library or overlay that will make your software &amp;quot;fully accessible&amp;quot; without putting in the effort.&lt;/p&gt;
&lt;p&gt;My commitment to my users is this: everything I develop will be built with accessibility in mind. I will test and improve my software to the best of my ability and knowledge. I will work around upstream issues, such as browser bugs and limitations, to the best of my ability and within reason.&lt;/p&gt;
&lt;p&gt;I&#39;m fully aware that I won&#39;t get it right every time for every user, so I invite the community to participate in this ongoing effort by submitting issues, pull requests, and discussions. Many accessibility improvements have already been made thanks to contributors submitting code, feedback, and suggestions.&lt;/p&gt;
&lt;p&gt;This is the path forward. Together, we will continue to make accessible software for as many users as possible.&lt;/p&gt;
&lt;p&gt;— Cory LaViska&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Converting a URL Object to a Plain Object in JavaScript</title>
		<link href="https://www.abeautifulsite.net/posts/converting-a-url-object-to-a-plain-object-in-java-script/"/>
		<updated>2023-03-22T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/converting-a-url-object-to-a-plain-object-in-java-script/</id>
		<content type="html">&lt;p&gt;I needed to convert a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/URL&quot;&gt;&lt;code&gt;URL&lt;/code&gt;&lt;/a&gt; object to a plain object yesterday. You might have used it before. It&#39;s pretty handy for working with URLs!&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; url &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;https://example.com/&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// URL {origin: &#39;https://example.com&#39;, protocol: &#39;https:&#39;, username: &#39;&#39;, password: &#39;&#39;, host: &#39;example.com&#39;, …}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Alas, you can&#39;t provide a &lt;code&gt;URL&lt;/code&gt; object as data to Handlebars &lt;a href=&quot;https://handlebarsjs.com/api-reference/runtime-options.html#options-to-control-prototype-access&quot;&gt;for security reasons&lt;/a&gt;. Essentially, allowing prototype properties in that context can lead to arbitrary code execution, which we definitely want to avoid.&lt;/p&gt;
&lt;p&gt;So the solution is simple! Turn the &lt;code&gt;URL&lt;/code&gt; object into a plain object and pass &lt;em&gt;that&lt;/em&gt; to Handlebars instead. Surely we can destructure it and move on.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; url &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;https://example.com/&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; plainObject &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;url &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;url &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// {}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Weird. It&#39;s empty. Let&#39;s try iterating over its keys instead. If we have the keys, we can loop through them and generate a plain object that way.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; url &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;https://example.com/&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// []&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An empty array? Oh, right, &lt;code&gt;URL&lt;/code&gt; uses &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol&quot;&gt;&lt;code&gt;Symbol&lt;/code&gt;&lt;/a&gt; internally so we have to use &lt;code&gt;getOwnPropertySymbols()&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; url &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;https://example.com/&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getOwnPropertySymbols&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// []&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ugh, it&#39;s still empty? What type of black magic is this?! Fine. Surely we can use &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect&quot;&gt;&lt;code&gt;Reflect&lt;/code&gt;&lt;/a&gt; to get the keys.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; url &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;https://example.com/&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Reflect&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ownKeys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// []&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Well, that&#39;s lame. Might as well do it the hard way…&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; url &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;https://example.com/&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; plainObject &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hash&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;host&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;hostname&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hostname&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;href&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;origin&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;origin&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;password&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;pathname&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pathname&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;port&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;protocol&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;protocol&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;search&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;searchParams&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;searchParams&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;username
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;plainObject&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// {hash: &#39;&#39;, host: &#39;example.com&#39;, hostname: &#39;example.com&#39;, href: &#39;https://example.com/path/to/file.ext&#39;, origin: &#39;https://example.com&#39;, …}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Well, this is what we want, but it&#39;s verbose and unreliable if future properties are added. Surely there must be a better way. After throwing this question over to &lt;a href=&quot;https://twitter.com/RogersKonnor&quot;&gt;Konnor Rogers&lt;/a&gt;, he found a solution.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; url &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;https://example.com/&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getOwnPropertyNames&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getPrototypeOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// (15) [&#39;origin&#39;, &#39;protocol&#39;, &#39;username&#39;, &#39;password&#39;, &#39;host&#39;, &#39;hostname&#39;, &#39;port&#39;, &#39;pathname&#39;, &#39;search&#39;, &#39;searchParams&#39;, &#39;hash&#39;, &#39;href&#39;, &#39;toJSON&#39;, &#39;toString&#39;, &#39;constructor&#39;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;(Cue the &amp;quot;doh!&amp;quot; moment…)&lt;/em&gt; 🙈&lt;/p&gt;
&lt;p&gt;Well, we finally have the keys so we can create a new object using them. Here&#39;s a function that neatly wraps the conversion up.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;urlToPlainObject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; keys &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getOwnPropertyNames&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getPrototypeOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; plainObject &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; keys&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    plainObject&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; plainObject&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; url &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;https://example.com/&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;urlToPlainObject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// {origin: &#39;https://example.com&#39;, protocol: &#39;https:&#39;, username: &#39;&#39;, password: &#39;&#39;, host: &#39;example.com&#39;, …}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Well, that was harder than it needed to be. Thanks, Konnor!&lt;/p&gt;
&lt;h2 id=&quot;update-(march-23%2C-2023)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/converting-a-url-object-to-a-plain-object-in-java-script/#update-(march-23%2C-2023)&quot;&gt;Update (March 23, 2023)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Special thanks to &lt;a href=&quot;https://twitter.com/WickyNilliams&quot;&gt;Nick Williams&lt;/a&gt; who &lt;a href=&quot;https://twitter.com/WickyNilliams/status/1638900597247078401?s=20&quot;&gt;discovered&lt;/a&gt; an even simpler approach.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; url &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;https://example.com/&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;field &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;field&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// (14) [&#39;origin&#39;, &#39;protocol&#39;, &#39;username&#39;, &#39;password&#39;, &#39;host&#39;, &#39;hostname&#39;, &#39;port&#39;, &#39;pathname&#39;, &#39;search&#39;, &#39;searchParams&#39;, &#39;hash&#39;, &#39;href&#39;, &#39;toJSON&#39;, &#39;toString&#39;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You might notice there are 14 fields instead of the original 15 now. That&#39;s because the &lt;code&gt;constructor&lt;/code&gt; property is omitted, which we didn&#39;t really want anyways. An updated version of our function looks like this, and it also discards the other non-string properties now.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; url &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;https://example.com/&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;urlToPlainObject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; plainObject &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; key &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;string&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      plainObject&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; plainObject&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;urlToPlainObject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// {origin: &#39;https://example.com&#39;, protocol: &#39;https:&#39;, username: &#39;&#39;, password: &#39;&#39;, host: &#39;example.com&#39;, …}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I have no idea why I didn&#39;t try a &lt;code&gt;for&lt;/code&gt; loop in the first place. 😅&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>The Term &quot;Headless Component&quot; is a Misnomer</title>
		<link href="https://www.abeautifulsite.net/posts/the-term-headless-component-is-a-misnomer/"/>
		<updated>2023-01-25T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/the-term-headless-component-is-a-misnomer/</id>
		<content type="html">&lt;p&gt;You&#39;ve likely heard the term &amp;quot;headless component&amp;quot; tossed around. The idea is you get solid, accessible components without any styles. A clean slate to style from scratch! But the structure (bones) and logic (head) are there. You&#39;re mostly adding styles.&lt;/p&gt;
&lt;p&gt;They should be called &amp;quot;skinless components.&amp;quot;&lt;/p&gt;
&lt;p&gt;And the thing about headless components is that, in my experience, people actually don&#39;t want to start from scratch. It&#39;s much, much easier to start with sensible base styles and customize from there.&lt;/p&gt;
&lt;p&gt;This is exactly what CSS was designed to do.&lt;/p&gt;
&lt;p&gt;Libraries such as &lt;a href=&quot;https://shoelace.style/&quot;&gt;Shoelace&lt;/a&gt; makes this easy for you. Its default theme has opinions for the sake of ease and consistency, but you can override them at a high level (design tokens) and/or at a low level (components) to achieve the look you want without having to write all the styles yourself.&lt;/p&gt;
&lt;h2 id=&quot;even-html-elements-aren&#39;t-headless&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/the-term-headless-component-is-a-misnomer/#even-html-elements-aren&#39;t-headless&quot;&gt;Even HTML elements aren&#39;t headless&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;User agents ship a default stylesheet that controls the appearance of most elements. We sometimes &amp;quot;reset&amp;quot; them, which is another misnomer because we&#39;re usually just normalizing the defaults that vary between browsers.&lt;/p&gt;
&lt;p&gt;But I digress…&lt;/p&gt;
&lt;p&gt;I&#39;m really happy that we&#39;re paying more attention to how things work and not just how they look. As web devs, we&#39;ve come a long way, especially in terms of accessibility and performance, but we seem to go from one extreme to another.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;It&#39;s OK when off the shelf components have opinions because it results in a lot less work!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;But what&#39;s important is that those opinions can be easily changed to work for your needs, preferably through a common and familiar syntax like CSS.&lt;/p&gt;
&lt;p&gt;Take it from someone who&#39;s built hundreds of components over the years. &lt;em&gt;You rarely want to style third-party components 100% from scratch.&lt;/em&gt; There&#39;s too much room for error. There are too many details and edge cases you&#39;re not going to get right.&lt;/p&gt;
&lt;h2 id=&quot;default-styles-gives-you-a-safety-net&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/the-term-headless-component-is-a-misnomer/#default-styles-gives-you-a-safety-net&quot;&gt;Default styles gives you a safety net&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Despite all that, headless components aren&#39;t bad! Any time you can avoid reinventing the wheel, you should. But if you want to spend more time building things and less time styling UI primitives, choose something that already has styles and sprinkle in your own customizations.&lt;/p&gt;
&lt;p&gt;One thing I will caution you to look out for is what I call &amp;quot;Bootstrap syndrome.&amp;quot; This occurs when you use a library&#39;s default styles with little to no customizations whatsoever. Your site ends up looking like every other site that uses Bootstrap as-is.&lt;/p&gt;
&lt;p&gt;This phenomenon started when devs would pull in &lt;code&gt;bootstrap.min.css&lt;/code&gt; from a CDN only to realize it wasn&#39;t easy to customize without Sass and a build step or &lt;em&gt;a lot&lt;/em&gt; of CSS. So they didn&#39;t.&lt;/p&gt;
&lt;p&gt;That problem has mostly been solved with CSS vars, but you still need to do the design work.&lt;/p&gt;
&lt;p&gt;Another consideration is, when you&#39;re not doing things from scratch, you can start building right away and incrementally improve the design as you go. That sounds like a huge win to me.&lt;/p&gt;
&lt;h2 id=&quot;making-a-choice&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/the-term-headless-component-is-a-misnomer/#making-a-choice&quot;&gt;Making a choice&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So you&#39;re left with:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Roll components &amp;amp; styles from scratch (bespoke)&lt;/li&gt;
&lt;li&gt;Roll styles from scratch (headless)*&lt;/li&gt;
&lt;li&gt;Only customize the things you need (e.g. &lt;a href=&quot;https://shoelace.style/&quot;&gt;Shoelace&lt;/a&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There&#39;s an element of design involved no matter what, but only one option lets you start building &lt;em&gt;right now.&lt;/em&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;small&gt;
&lt;p&gt;*&lt;em&gt;But Cory, [headless lib] has themes I can pick from!&lt;/em&gt; If you&#39;re going to go headless, this is how you should start. Pick a theme, preferably one that&#39;s very comprehensive, and start there. But keep in mind that third-party themes may be buggy or incomplete too!&lt;/p&gt;
&lt;p&gt;This post was originally a &lt;a href=&quot;https://x.com/claviska/status/1618346116176826372&quot;&gt;Twitter thread&lt;/a&gt;.&lt;/p&gt;
&lt;/small&gt;
</content>
	</entry>
	
	<entry>
		<title>Shoelace 2.0</title>
		<link href="https://www.abeautifulsite.net/posts/shoelace-2/"/>
		<updated>2023-01-24T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/shoelace-2/</id>
		<content type="html">&lt;p&gt;It&#39;s been three years since I broke ground on &lt;a href=&quot;https://shoelace.style/&quot;&gt;Shoelace 2.0&lt;/a&gt;. Between then and now, the project has amassed &lt;a href=&quot;https://www.jsdelivr.com/package/npm/@shoelace-style/shoelace&quot;&gt;over 300 million monthly hits on jsDelivr&lt;/a&gt; and, as of today, it is jsDelivr&#39;s &lt;a href=&quot;https://www.jsdelivr.com/statistics&quot;&gt;73rd most popular project&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And that was just the beta version.&lt;/p&gt;
&lt;p&gt;Today, I&#39;m happy to announce that the first stable release of Shoelace is finally available!&lt;/p&gt;
&lt;p&gt;First and foremost, I&#39;d like to say thank you to all my users. I&#39;ve poured my heart and soul into this library and I&#39;m thrilled to see so many people building with it. You continue to inspire me every day!&lt;/p&gt;
&lt;p&gt;For those unfamiliar, Shoelace is a free, open source library of Web Components you can use to build websites and web applications. There are over 50 accessible, handcrafted user interface components to choose from, and you can use them in any framework you want!&lt;/p&gt;
&lt;h2 id=&quot;why-choose-web-components&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/shoelace-2/#why-choose-web-components&quot;&gt;Why Choose Web Components&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Web_Components&quot;&gt;Web Components&lt;/a&gt; are built using Web Standards, meaning they don&#39;t require a framework to use. You can think of them as custom HTML elements, because that&#39;s exactly what they are!&lt;/p&gt;
&lt;p&gt;And because they&#39;re just HTML elements, you can use them in &lt;a href=&quot;https://custom-elements-everywhere.com/&quot;&gt;any framework you want&lt;/a&gt;, such as React, Vue, Angular, Svelte, Solid, and more. This makes Web Components a great candidate for your next design system! In fact, Shoelace acts as a design system starter kit, allowing you to &lt;a href=&quot;https://shoelace.style/getting-started/customizing&quot;&gt;customize it&lt;/a&gt; to suit your needs.&lt;/p&gt;
&lt;p&gt;Shoelace is built with &lt;a href=&quot;https://shoelace.style/resources/accessibility&quot;&gt;accessibility in mind&lt;/a&gt; and comes with both light and dark themes out of the box. Why spend months building your own UI primitives (i.e. buttons, dialogs, form controls, tabs, etc.) when you can get dozens of battle-tested components and start building with them &lt;em&gt;right now&lt;/em&gt;?&lt;/p&gt;
&lt;p&gt;I invite you to &lt;a href=&quot;https://shoelace.style/?id=new-to-web-components&quot;&gt;learn more about Web Components&lt;/a&gt; to better understand how you and your organization can benefit from them.&lt;/p&gt;
&lt;h2 id=&quot;what&#39;s-next&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/shoelace-2/#what&#39;s-next&quot;&gt;What&#39;s Next&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While this release is a major milestone for Shoelace, I feel like we&#39;re still just getting started. There&#39;s always more to do — more features, more tests, more polish — and with the support of the amazing folks at &lt;a href=&quot;https://blog.fontawesome.com/shoelace-joins-font-awesome/&quot;&gt;Font Awesome&lt;/a&gt;, we&#39;re going to deliver an incredible amount of value in the coming year.&lt;/p&gt;
&lt;p&gt;Sorry, no spoilers! But you&#39;ll be hearing a lot about Shoelace as we continue our journey to become everyone&#39;s favorite open source Web Component library.&lt;/p&gt;
&lt;p&gt;Before I go, I&#39;d like to share some interesting stats about this release!&lt;/p&gt;
&lt;h2 id=&quot;shoelace-2.0-in-numbers&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/shoelace-2/#shoelace-2.0-in-numbers&quot;&gt;Shoelace 2.0 in Numbers&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Development of Shoelace 2.0 started in January 2020. The first beta was released on &lt;a href=&quot;https://github.com/shoelace-style/shoelace/releases/tag/v2.0.0-beta.1&quot;&gt;July 15, 2020&lt;/a&gt;. Since then, Shoelace has grown quite a bit! Here&#39;s a look at some stats from the project.*&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://shoelace.style/&quot;&gt;55 components&lt;/a&gt; have been built&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/shoelace-style/shoelace/commits/next&quot;&gt;Over 2,500 commits&lt;/a&gt; have been made to the project&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/shoelace-style/shoelace/graphs/contributors&quot;&gt;85 people&lt;/a&gt; have contributed to the project&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/shoelace-style/shoelace/issues?q=is%3Aissue+is%3Aclosed&quot;&gt;669 issues&lt;/a&gt; have been filed on GitHub&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/shoelace-style/shoelace/pulls&quot;&gt;274 pull requests&lt;/a&gt; have been opened&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/shoelace-style/shoelace/discussions&quot;&gt;More than 150 discussions&lt;/a&gt; have been started on GitHub&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://discord.com/invite/mg8f26C&quot;&gt;Over 500 people&lt;/a&gt; have joined the Shoelace community on Discord&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jsdelivr.com/package/npm/@shoelace-style/shoelace&quot;&gt;Over 300 million CDN hits&lt;/a&gt; per month&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/@shoelace-style/shoelace&quot;&gt;Over 13,000 npm downloads&lt;/a&gt; per week&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jsdelivr.com/statistics&quot;&gt;73rd most popular project&lt;/a&gt; on jsDelivr&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.producthunt.com/products/shoelace-css&quot;&gt;#2 product of the day&lt;/a&gt; on Product Hunt (July 25, 2020)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*Stats recorded on January 24, 2023&lt;/p&gt;
&lt;h2 id=&quot;special-thanks&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/shoelace-2/#special-thanks&quot;&gt;Special Thanks&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I&#39;d like to extend a very special thank you to every single contributor who worked to make this possible. Everyone who&#39;s filed a bug, submitted a PR, requested a feature, started a discussion, helped with testing, and advocated for the project. You are just as responsible for Shoelace&#39;s success as I am. I&#39;d also like to thank the folks at &lt;a href=&quot;https://fontawesome.com/&quot;&gt;Font Awesome&lt;/a&gt; for recognizing Shoelace&#39;s potential and &lt;a href=&quot;https://blog.fontawesome.com/shoelace-joins-font-awesome/&quot;&gt;believing in me&lt;/a&gt; to make it happen.&lt;/p&gt;
&lt;p&gt;Thank you! And keep building &lt;em&gt;awesome&lt;/em&gt; stuff!&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;This post was &lt;a href=&quot;https://blog.fontawesome.com/shoelace-2-0-is-official/&quot;&gt;originally published on the Font Awesome blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Installing Shoelace in a React App</title>
		<link href="https://www.abeautifulsite.net/posts/installing-shoelace-in-a-react-app/"/>
		<updated>2022-12-15T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/installing-shoelace-in-a-react-app/</id>
		<content type="html">&lt;p&gt;Although &lt;a href=&quot;https://www.shoelace.style/&quot;&gt;Shoelace&lt;/a&gt; is a web component library, it ships &lt;a href=&quot;https://shoelace.style/frameworks/react&quot;&gt;React wrappers&lt;/a&gt; that lets you use the library idiomatically in React. This video shows you how to install Shoelace in a brand new &lt;a href=&quot;https://create-react-app.dev/&quot;&gt;Create React App&lt;/a&gt;.&lt;/p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/Ku2mJCJgvLs&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;If you found this video helpful, please &lt;a href=&quot;https://www.youtube.com/c/CoryLaViska&quot;&gt;subscribe to my channel on YouTube&lt;/a&gt; and &lt;a href=&quot;https://x.com/claviska&quot;&gt;follow me on Twitter&lt;/a&gt; for more helpful Shoelace tips!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Why You Should Prefix Custom Events</title>
		<link href="https://www.abeautifulsite.net/posts/why-you-should-prefix-custom-events/"/>
		<updated>2022-12-12T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/why-you-should-prefix-custom-events/</id>
		<content type="html">&lt;p&gt;Similar to how every custom element must contain a dash, I like to pretend that every custom event must also contain a dash. This removes all ambiguity between native events and custom events.&lt;/p&gt;
&lt;p&gt;Therefore, I prefix all custom events in &lt;a href=&quot;https://shoelace.style/&quot;&gt;Shoelace&lt;/a&gt; with &lt;code&gt;sl-&lt;/code&gt;. It may seem contradictory that &lt;a href=&quot;https://www.abeautifulsite.net/posts/custom-event-names-and-the-bubbling-problem/&quot;&gt;I&#39;ve chosen to follow the platform&#39;s convention for emitting events&lt;/a&gt; but not for naming them. There&#39;s a good reason, though.&lt;/p&gt;
&lt;p&gt;To preserve encapsulation, events that emit from &lt;em&gt;within&lt;/em&gt; a shadow root are retargeted so they appear to come from the host element. If a custom element has three buttons in its shadow root, a click on any of those buttons will appear to come from the host element, as demonstrated below.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- A custom element with three buttons in its shadow root --&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;three-buttons&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;three-buttons&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Define the custom element&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ThreeButtons&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HTMLElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;attachShadow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;open&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;token comment&quot;&gt;// There are better ways, but for brevity…&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;shadowRoot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;innerHTML &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
        &amp;lt;button type=&quot;button&quot;&gt;First&amp;lt;/button&gt;
        &amp;lt;button type=&quot;button&quot;&gt;Second&amp;lt;/button&gt;
        &amp;lt;button type=&quot;button&quot;&gt;Third&amp;lt;/button&gt;
      &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Register it&lt;/span&gt;
  customElements&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;three-buttons&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ThreeButtons&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Notice how the target is the same, regardless of which button you click?&lt;/span&gt;
  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;three-buttons&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;click&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token parameter&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://codepen.io/claviska/pen/JjZqeLJ&quot;&gt;Try it on CodePen&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Retargeting is necessary and sometimes even convenient but, because of it, you might observe a seemingly endless number of events getting emitted from the host element as the user interacts with its internals.&lt;/p&gt;
&lt;p&gt;So how can you differentiate a &lt;code&gt;click&lt;/code&gt; event emitted by an internal element from a custom &lt;code&gt;click&lt;/code&gt; event emitted by the host?&lt;/p&gt;
&lt;p&gt;You can&#39;t rely on the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Event/eventPhase&quot;&gt;event phase&lt;/a&gt; because it will show &lt;code&gt;AT_TARGET&lt;/code&gt;. You probably shouldn&#39;t use &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Event/composedPath&quot;&gt;&lt;code&gt;Event.composedPath()&lt;/code&gt;&lt;/a&gt; because that breaks encapsulation, relies on private structures that can change, and doesn&#39;t work for closed shadow roots.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(Flips table over and walks out)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;To do this, devs would need to listen to and prevent &lt;em&gt;every event&lt;/em&gt; that might be retargeted from any applicable element inside the shadow root, and then re-emit an even of the same name with some kind of payload in &lt;code&gt;event.detail&lt;/code&gt; to help differentiate. This would mean a lot of unnecessary code and clutter, and even the most astute custom element authors will fail to get it right from time to time.&lt;/p&gt;
&lt;p&gt;Instead, you can simply prefix custom events to sidestep this problem.*&lt;/p&gt;
&lt;p&gt;Another benefit of prefixing is that, in the context of a web component library, it&#39;s immediately clear which events belong to a particular library. It&#39;s fairly obvious that &lt;code&gt;sl-change&lt;/code&gt; is a Shoelace event, for example.&lt;/p&gt;
&lt;small&gt;
&lt;p&gt;*It could be argued that one shouldn&#39;t prefix custom events and should instead prevent retargeted events from conflicting with custom events, but I avoid this pattern because it breaks the expectation that consumers may have for handling retargeted events.&lt;/p&gt;
&lt;/small&gt;
</content>
	</entry>
	
	<entry>
		<title>Custom Event Names and the Bubbling Problem</title>
		<link href="https://www.abeautifulsite.net/posts/custom-event-names-and-the-bubbling-problem/"/>
		<updated>2022-12-12T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/custom-event-names-and-the-bubbling-problem/</id>
		<content type="html">&lt;p&gt;The topic of custom element event names comes up every now and then, especially from &lt;a href=&quot;https://shoelace.style/&quot;&gt;Shoelace&lt;/a&gt; users who get confused when events of the same name are emitted from different components.&lt;/p&gt;
&lt;p&gt;Take &lt;a href=&quot;https://shoelace.style/components/details&quot;&gt;&lt;code&gt;&amp;lt;sl-details&amp;gt;&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://shoelace.style/components/dialog&quot;&gt;&lt;code&gt;&amp;lt;sl-dialog&amp;gt;&lt;/code&gt;&lt;/a&gt;, and &lt;a href=&quot;https://shoelace.style/components/dropdown&quot;&gt;&lt;code&gt;&amp;lt;sl-dropdown&amp;gt;&lt;/code&gt;&lt;/a&gt;, for example. They all emit &lt;code&gt;sl-show&lt;/code&gt; and &lt;code&gt;sl-hide&lt;/code&gt; events, allowing you to hook into their lifecycle as they open and close. Occasionally, someone will nest a component inside another, listen for an event such as &lt;code&gt;sl-hide&lt;/code&gt;, and wonder why the callback executes at the &amp;quot;wrong time.&amp;quot;&lt;/p&gt;
&lt;p&gt;In this example, you can see that we have an &lt;code&gt;&amp;lt;sl-dropdown&amp;gt;&lt;/code&gt; inside of an &lt;code&gt;&amp;lt;sl-dialog&amp;gt;&lt;/code&gt;. Both of these components emit &lt;code&gt;sl-show&lt;/code&gt; and &lt;code&gt;sl-hide&lt;/code&gt; events.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;sl-dialog&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Dialog&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Note how the dropdown is nested inside the dialog --&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;sl-dropdown&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;sl-button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;slot&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;trigger&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;caret&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Open and close me&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;sl-button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;sl-menu&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;sl-menu-item&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Option 1&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;sl-menu-item&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;sl-menu-item&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Option 2&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;sl-menu-item&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;sl-menu-item&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Option 3&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;sl-menu-item&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;sl-menu&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;sl-dropdown&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;sl-dialog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;sl-button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;open&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Open Dialog&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;sl-button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; dialog &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;sl-dialog&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; openButton &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;open&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Show the dialog when the button is clicked&lt;/span&gt;
  openButton&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;click&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; dialog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;show&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Listen for the sl-show event&lt;/span&gt;
  dialog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;sl-show&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token parameter&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;The dialog has opened…or has it?&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Listen for the sl-hide event&lt;/span&gt;
  dialog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;sl-hide&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token parameter&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;The dialog has closed…or has it?&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://codepen.io/claviska/pen/vYrwjyP&quot;&gt;Try it on CodePen&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The logic above is faulty because it runs when the dialog &lt;em&gt;or&lt;/em&gt; any of the dialog&#39;s children emit the &lt;code&gt;sl-show&lt;/code&gt; or &lt;code&gt;sl-hide&lt;/code&gt; event. This occurs due to &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#event_bubbling&quot;&gt;event bubbling&lt;/a&gt;, which is an incredibly useful feature of the platform. When events bubble up, listeners on ancestor elements will execute. This enables an extremely useful feature called &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#event_delegation&quot;&gt;event delegation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Alas, this is also a source of confusion.&lt;/p&gt;
&lt;p&gt;Fortunately, there are a number of easy ways to work around it.&lt;/p&gt;
&lt;h3 id=&quot;checking-the-target&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/custom-event-names-and-the-bubbling-problem/#checking-the-target&quot;&gt;Checking the Target&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Events are emitted with a &lt;code&gt;target&lt;/code&gt; property that you can inspect to determine which element emitted it. Thus, we can modify the handlers from the previous example to ensure the target is the same dialog we attached the listener to.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Listen for the sl-show event&lt;/span&gt;
dialog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;sl-show&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token parameter&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; dialog&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;The dialog has opened&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Listen for the sl-hide event&lt;/span&gt;
dialog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;sl-hide&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token parameter&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; dialog&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;The dialog has closed&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://codepen.io/claviska/pen/VwdOxdO&quot;&gt;Try it on CodePen&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;checking-the-current-target&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/custom-event-names-and-the-bubbling-problem/#checking-the-current-target&quot;&gt;Checking the Current Target&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Another way is to compare &lt;code&gt;Event.currentTarget&lt;/code&gt;, which effectively does the same thing.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Listen for the sl-show event&lt;/span&gt;
dialog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;sl-show&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token parameter&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;currentTarget&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;The dialog has opened&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Listen for the sl-hide event&lt;/span&gt;
dialog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;sl-hide&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token parameter&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;currentTarget&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;The dialog has closed&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://codepen.io/claviska/pen/eYKabQM&quot;&gt;Try it on CodePen&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;checking-the-event-phase&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/custom-event-names-and-the-bubbling-problem/#checking-the-event-phase&quot;&gt;Checking the Event Phase&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Here&#39;s yet another way to ensure the event was emitted by the expected element. It&#39;s a bit more verbose, but it doesn&#39;t require a reference. Instead, we can inspect &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Event/eventPhase&quot;&gt;&lt;code&gt;Event.eventPhase&lt;/code&gt;&lt;/a&gt; to determine which &lt;em&gt;phase&lt;/em&gt; the event is in. In this example, the listener is attached directly to the dialog, so we&#39;re interested in the &lt;code&gt;AT_TARGET&lt;/code&gt; phase.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Listen for the sl-show event&lt;/span&gt;
dialog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;sl-show&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token parameter&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;eventPhase &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; Event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;AT_TARGET&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;The dialog has opened&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Listen for the sl-hide event&lt;/span&gt;
dialog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;sl-hide&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token parameter&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;eventPhase &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; Event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;AT_TARGET&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;The dialog has closed&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://codepen.io/claviska/pen/poKmxxQ&quot;&gt;Try it on CodePen&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;why-not-use-unique-event-names%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/custom-event-names-and-the-bubbling-problem/#why-not-use-unique-event-names%3F&quot;&gt;Why Not Use Unique Event Names?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It has been proposed numerous times that custom elements should emit events with unique names to avoid such confusion. For example, instead of emitting &lt;code&gt;sl-show&lt;/code&gt; for multiple components, event names might be named based on their tag, e.g. &lt;code&gt;sl-dialog-show&lt;/code&gt; and &lt;code&gt;sl-dropdown-show&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I appreciate the idea, but this just isn&#39;t how events works. If you click a &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; you get a &lt;code&gt;click&lt;/code&gt; event, not a &lt;code&gt;button-click&lt;/code&gt; event. If you set focus to an &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt;, you get a &lt;code&gt;focus&lt;/code&gt; event, not an &lt;code&gt;input-focus&lt;/code&gt; event. Besides, you still wouldn’t be able to differentiate the target element this way since elements of the same type can often be nested inside others.&lt;/p&gt;
&lt;p&gt;For the sake of consistency with the platform, I consider this suggestion an anti-pattern that should be avoided in custom elements. Instead, developers must understand that many events bubble — including native ones — and they should be doing these checks any time elements are nested to avoid unexpected behaviors.&lt;/p&gt;
&lt;p&gt;This problem isn&#39;t exclusive to custom elements.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>The Future of Shoelace</title>
		<link href="https://www.abeautifulsite.net/posts/the-future-of-shoelace/"/>
		<updated>2022-10-17T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/the-future-of-shoelace/</id>
		<content type="html">&lt;p&gt;It&#39;s been more than two years since the &lt;a href=&quot;https://github.com/shoelace-style/shoelace/releases/tag/v2.0.0-beta.1&quot;&gt;beta release of Shoelace 2.0&lt;/a&gt;, which was the first version of the project to ship Web Components. What started off as a fun side project has quickly grown to become one of the most recognized Web Component libraries in the world. As of today, Shoelace receives &lt;a href=&quot;https://twitter.com/shoelace_style/status/1580897727093035009?s=20&amp;amp;t=1CE1cightq5j_GHgzsvF8w&quot;&gt;more than 100 million&lt;/a&gt; monthly CDN hits on &lt;a href=&quot;https://www.jsdelivr.com/package/npm/@shoelace-style/shoelace&quot;&gt;jsDelivr&lt;/a&gt;, and that number continues to grow.&lt;/p&gt;
&lt;p&gt;Thank you for that. I&#39;ve poured my heart and soul into this library and I&#39;m honored by the overwhelmingly positive feedback Shoelace receives on a daily basis.&lt;/p&gt;
&lt;p&gt;But today, I want to talk to you about the future.&lt;/p&gt;
&lt;p&gt;Shoelace is and always has been a side project. I spend a lot of time maintaining it because I &lt;em&gt;enjoy&lt;/em&gt; working on it. However, the effort I put into Shoelace is &lt;em&gt;in addition&lt;/em&gt; to my full-time position as a technical lead at Microsoft.&lt;/p&gt;
&lt;p&gt;Lately, I haven&#39;t been able to find enough spare time to move the project forward. The more hours I carve out to work on it, the less I have for myself and my family. I&#39;ve been careful not to burn out. I take breaks when I need to. But there&#39;s so much more that needs to be done.&lt;/p&gt;
&lt;p&gt;Shoelace has reached the point where it demands a full-time effort, otherwise its potential will never be realized. That&#39;s why I&#39;ve decided to bid farewell to Microsoft in November.&lt;/p&gt;
&lt;p&gt;To be honest, that&#39;s a really, really hard thing for me to say. Microsoft has been great to me. I have an amazing manager, we&#39;ve built a fantastic team, and I get to work with Web Components every day! In many ways, it&#39;s a dream job and that makes it very hard to give up — especially for an open source project that doesn&#39;t have any revenue.&lt;/p&gt;
&lt;p&gt;If that seems crazy, well, there&#39;s a bit more to the story. Let me explain…&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;A few months ago, I found myself on a plane to Bentonville, Arkansas to meet with the folks who created &lt;a href=&quot;https://fontawesome.com/&quot;&gt;Font Awesome&lt;/a&gt;. We spent days talking about Web Standards, open source, and Shoelace. I had a great time and learned a lot about their values and how they were able to turn an open source project into a sustainable business.&lt;/p&gt;
&lt;p&gt;What came of that trip was something I never expected — an opportunity to work on Shoelace full-time. I thought about it long and hard and ultimately decided that, given my current obligations, I can&#39;t do this all on my own anymore. And who better to team up with than an amazing group of people who have been there and done it before?!&lt;/p&gt;
&lt;p&gt;It&#39;s bittersweet, but as I close this chapter at Microsoft, I will be starting a new chapter with the folks at Font Awesome. I will be responsible for building Shoelace into a sustainable open source project under their expert guidance.&lt;/p&gt;
&lt;p&gt;You can expect the same commitment to open source as always! But now, with my full attention and more resources, you&#39;ll get bug fixes even faster; you&#39;ll get features I&#39;ve wanted to build for a very long time; and you&#39;ll get even more as Shoelace continues to grow!&lt;/p&gt;
&lt;p&gt;Thank you for your support and contributions up to this point. The last two years have been an amazing journey for me, and I&#39;m very excited to see what the future holds.&lt;/p&gt;
&lt;p&gt;If you&#39;re not following &lt;a href=&quot;https://twitter.com/shoelace_style&quot;&gt;Shoelace on Twitter&lt;/a&gt;, now would be a good time to hit the button to keep up with the latest news.&lt;/p&gt;
&lt;p&gt;Hang on, everyone! Shoelace is about to get even more &lt;em&gt;awesome&lt;/em&gt;.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>A Web Component Story</title>
		<link href="https://www.abeautifulsite.net/posts/a-web-component-story/"/>
		<updated>2022-09-30T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/a-web-component-story/</id>
		<content type="html">&lt;p&gt;Gather &#39;round, it&#39;s story time.&lt;/p&gt;
&lt;p&gt;A number of years ago, I was hired by a company to rebuild a component library for their design system. The one they were replacing was built with AngularJS, but AngularJS was old and rickety and nobody wanted to use it anymore. Plus, many teams had moved on to other frameworks and one team even preferred doing everything with vanilla JS.&lt;/p&gt;
&lt;p&gt;But the company couldn&#39;t hire for AngularJS. There was no talent available. Devs had moved on. Nobody wanted to work with a &amp;quot;legacy framework.&amp;quot;&lt;/p&gt;
&lt;p&gt;So they had to build something new to get out of that ecosystem. They talked about building a new component library in modern Angular. Or maybe React. A handful of engineers wanted Vue.&lt;/p&gt;
&lt;p&gt;But they knew that whatever framework they chose, they would be locking teams into it or forcing them to build their own components. This would mean duplicating effort and risking stylistic and behavioral deviations — an inevitable side effect of competing libraries.&lt;/p&gt;
&lt;p&gt;They also knew that they&#39;d be doing this again in a few years if they picked any of today&#39;s popular frameworks, so they decided to give Web Components a try.&lt;/p&gt;
&lt;p&gt;So that&#39;s what we built, and that&#39;s what they still use to this day. It no longer matters if their teams want to build with React, Vue, Svelte, Solid, or whatever tomorrow brings.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nobody is forced to use a specific framework&lt;/li&gt;
&lt;li&gt;Nobody needs to reinvent UI primitives&lt;/li&gt;
&lt;li&gt;Upgrading or switching frameworks is much easier&lt;/li&gt;
&lt;li&gt;No duplicate efforts&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At this point, you might be thinking &amp;quot;we only use React, so who cares?&amp;quot; And you can get away with that for awhile, especially if you&#39;re a single team or a small shop. I get it. React feels good and it&#39;s sticky. But all frameworks eventually fizzle out.&lt;/p&gt;
&lt;p&gt;Thanks to Web Components, large companies are realizing you don&#39;t need to rebuild buttons and other UI primitives every few years. Teams don&#39;t need to argue about frameworks anymore. You can have your cake and eat it too!&lt;/p&gt;
&lt;p&gt;It&#39;s already happening on a large scale at some of the largest companies in the world, but the impact isn&#39;t limited to big players — everyone can benefit from Web Components today.&lt;/p&gt;
&lt;p&gt;To be clear, I&#39;m not suggesting you throw out your framework and go all in on Web Components...Web Components are &lt;em&gt;complementary&lt;/em&gt; to frameworks! In 2022, I strongly suggest building your design system with them. Knock out the UI primitives and patterns that all teams use and give devs the freedom to build with whatever framework(s) they want!&lt;/p&gt;
&lt;p&gt;Any org that goes all in on a single framework will eventually find themselves swimming upstream to hire talent to maintain legacy code and avoid framework rot. But you can reduce this burden (and the associated costs) by using Web Components in your design system.&lt;/p&gt;
&lt;p&gt;Remember that &lt;a href=&quot;https://www.abeautifulsite.net/posts/design-systems-arent-cheap/&quot;&gt;design systems aren&#39;t cheap&lt;/a&gt;. It takes a lot of time to redesign and rebuild dozens of components, so why keep doing it every few years? It costs too much and it prevents you from shipping faster.&lt;/p&gt;
&lt;p&gt;Here&#39;s a quick case study from an open source UI library called &lt;a href=&quot;https://element.eleme.io/#/en-US&quot;&gt;Element UI&lt;/a&gt;. This is a very popular Vue 2 library, but breaking changes in Vue 3 meant the library no longer worked! They had to build and maintain a &lt;a href=&quot;https://element-plus.org/en-US/&quot;&gt;completely different version of the library&lt;/a&gt;, and now they maintain two separate versions — one for Vue 2 users and one for Vue 3 users. 🤦🏻‍♂️&lt;/p&gt;
&lt;p&gt;This is what happens when you go all in on a framework for UI primitives. Imagine having to maintain multiple versions of your component library for each framework — &lt;em&gt;and each major version&lt;/em&gt; — you want to support.&lt;/p&gt;
&lt;p&gt;Thanks to Web Components, this it totally avoidable!&lt;/p&gt;
&lt;p&gt;A common criticism I hear is that Web Components aren&#39;t perfect, to which I&#39;ll agree. No, they&#39;re not perfect. But they&#39;re pretty damn good, they&#39;re part of the standard, and we can collectively work to improve any shortcomings they might have.&lt;/p&gt;
&lt;p&gt;I&#39;ll take platform-based interoperable components over framework churn any day of the week. ✌🏻&lt;/p&gt;
&lt;hr /&gt;
&lt;small&gt;
&lt;p&gt;Shameless plug: you should take a look at &lt;a href=&quot;https://shoelace.style/&quot;&gt;Shoelace&lt;/a&gt; if you&#39;re looking for an awesome library of web components.&lt;/p&gt;
&lt;p&gt;This post was originally a &lt;a href=&quot;https://x.com/claviska/status/1575505182175408128&quot;&gt;Twitter thread&lt;/a&gt;.&lt;/p&gt;
&lt;/small&gt;
</content>
	</entry>
	
	<entry>
		<title>Not Everything Can Be Feature Detected</title>
		<link href="https://www.abeautifulsite.net/posts/not-everything-can-be-feature-detected/"/>
		<updated>2022-08-15T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/not-everything-can-be-feature-detected/</id>
		<content type="html">&lt;p&gt;In the early days of Web browsers, it was extremely common to see user agent checks in JavaScript. Sometimes, you&#39;d write the same code in two or three different ways to support various browsers. Code such as that shown below allowed webpages to work in browsers like Netscape Navigator and Internet Explorer, who didn&#39;t always agree on how features should be implemented.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;navigator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userAgent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;indexOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;MSIE&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// code for Internet Explorer&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// code for other browsers&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To exacerbate this, Internet Explorer introduced a syntax for &lt;a href=&quot;https://en.wikipedia.org/wiki/Conditional_comment&quot;&gt;conditional comments&lt;/a&gt; that allowed developers to provide IE-specific code. It even allowed devs to target specific &lt;em&gt;versions&lt;/em&gt; of Internet Explorer.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!--[if gte IE 6 ]&gt;
  &amp;lt;p&gt;Only IE 6 and above will see this&amp;lt;/p&gt;
&amp;lt;![endif]--&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This may seem like madness in 2022, but it was an absolute necessity to make your web app work everywhere. Some of you might remember those little &lt;em&gt;This site best viewed in Internet Explorer&lt;/em&gt; badges.&lt;/p&gt;
&lt;p&gt;Eventually, and probably largely due to &lt;a href=&quot;https://modernizr.com/&quot;&gt;Modernizr&lt;/a&gt;, we started telling developers to detect &lt;em&gt;features&lt;/em&gt; instead of &lt;em&gt;browsers&lt;/em&gt;. The idea was that, as standards became more established and browser development picked up after the IE6 lull, it was more reliable to test for specific features rather than specific browser versions.&lt;/p&gt;
&lt;p&gt;These days, feature detection is the de facto winner over browser sniffing, which is mostly a good thing. Alas, some developers take things from one extreme to another. Over the years, I&#39;ve stumbled upon numerous code snippets where, instead of detecting a &lt;em&gt;feature&lt;/em&gt;, the developer was detecting &lt;em&gt;something completely unrelated to the feature&lt;/em&gt; and using that as a flag to sniff the browser.&lt;/p&gt;
&lt;p&gt;The line of thinking goes like this: &amp;quot;&lt;em&gt;Feature A&lt;/em&gt; only works in Firefox, but I can&#39;t detect &lt;em&gt;Feature A&lt;/em&gt; directly. Hmm...but I &lt;em&gt;can&lt;/em&gt; detect &lt;em&gt;Feature B&lt;/em&gt; which also only works in Firefox, so I&#39;ll use that to determine whether &lt;em&gt;Feature A&lt;/em&gt; is supported!&amp;quot; (I&#39;m intentionally omitting links to avoid calling anyone out.)&lt;/p&gt;
&lt;p&gt;Hopefully, you can see why this is a bad idea. One day, Firefox might implement &lt;em&gt;Feature A&lt;/em&gt; before &lt;em&gt;Feature B&lt;/em&gt;, which means your test is now useless. Or, the opposite could happen and they ship &lt;em&gt;Feature B&lt;/em&gt; before &lt;em&gt;Feature A&lt;/em&gt;, leaving you with a broken website.&lt;/p&gt;
&lt;p&gt;Alas, feature detection isn&#39;t always straightforward, so occasionally developers do things like this because it seems better than user agent sniffing. Which brings me to my next point...&lt;/p&gt;
&lt;h2 id=&quot;not-everything-can-be-feature-detected&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/not-everything-can-be-feature-detected/#not-everything-can-be-feature-detected&quot;&gt;Not Everything Can Be Feature Detected&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You see, not &lt;em&gt;everything&lt;/em&gt; can be feature detected. One example can be found in the &lt;a href=&quot;https://github.com/shoelace-style/shoelace/blob/147d1f048b86ad4317b71238fd8560da5ea19927/src/components/input/input.ts#L373-L377&quot;&gt;Shoelace code for &lt;code&gt;&amp;lt;sl-input&amp;gt;&lt;/code&gt;&lt;/a&gt;. This component acts as a supercharged &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; element, offering more features than a standard form control. One of its features, for example, is a clear button. Many browsers will show their own clear button for &lt;code&gt;&amp;lt;input type=&amp;quot;search&amp;quot;&amp;gt;&lt;/code&gt;, but not for other input types. Shoelace, on the other hand, allows you to add a custom clear button to &lt;em&gt;any&lt;/em&gt; input type while providing a consistent UI in all browsers.&lt;/p&gt;
&lt;p&gt;The problem is that Firefox adds its own clear button to date inputs, which resulted in this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/shoelace-input-with-two-clear-buttons.png&quot; alt=&quot;A Shoelace date input shown with two clear buttons, one custom and one by the browser.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;No other browsers do this, and there&#39;s &lt;a href=&quot;https://github.com/shoelace-style/shoelace/issues/791&quot;&gt;no obvious way to turn it off or hide it&lt;/a&gt; in Firefox. Furthermore, you can&#39;t feature detect it — or at least we haven&#39;t discovered a way to do so.&lt;/p&gt;
&lt;p&gt;This is where some developers might lean on detecting &lt;em&gt;Feature B&lt;/em&gt; to support &lt;em&gt;Feature A&lt;/em&gt; to avoid browser sniffing — but we&#39;ve already discussed why that&#39;s a bad idea.&lt;/p&gt;
&lt;p&gt;So what&#39;s a developer to do?&lt;/p&gt;
&lt;h2 id=&quot;calling-out-user-agent-checks&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/not-everything-can-be-feature-detected/#calling-out-user-agent-checks&quot;&gt;Calling Out User Agent Checks&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The solution here is to do the thing that&#39;s become taboo...we need to sniff the user agent string for Firefox! That can be done with ease:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; isFirefox &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; navigator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userAgent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Firefox&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But developers aren&#39;t the only ones calling out browser sniffing. Running this code in Chrome will yield a notice in the dev console.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A page or script is accessing at least one of &lt;code&gt;navigator.userAgent&lt;/code&gt;, &lt;code&gt;navigator.appVersion&lt;/code&gt;, and &lt;code&gt;navigator.platform&lt;/code&gt;. Starting in Chrome 101, the amount of information available in the User Agent string will be reduced.&lt;/p&gt;
&lt;p&gt;To fix this issue, replace the usage of &lt;code&gt;navigator.userAgent&lt;/code&gt;, &lt;code&gt;navigator.appVersion&lt;/code&gt;, and &lt;code&gt;navigator.platform&lt;/code&gt; with feature detection, progressive enhancement, or migrate to &lt;code&gt;navigator.userAgentData&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;While sniffing is usually a bad idea, Chrome isn&#39;t exactly saying that here. It&#39;s letting us know that they&#39;re going to be reducing the information provided in &lt;code&gt;navigator.userAgent&lt;/code&gt;, likely to mitigate &lt;a href=&quot;https://www.mozilla.org/en-US/firefox/features/block-fingerprinting/&quot;&gt;fingerprinting&lt;/a&gt;. This check will probably continue to work for a long time, but if we want to eliminate this notice from the console, we need to use an alternative. That&#39;s where &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Navigator/userAgentData&quot;&gt;&lt;code&gt;navigator.userAgentData&lt;/code&gt;&lt;/a&gt; comes in.&lt;/p&gt;
&lt;p&gt;Currently, &lt;a href=&quot;https://caniuse.com/mdn-api_navigator_useragentdata&quot;&gt;support is limited&lt;/a&gt; to Chromium-based browsers, but we can still leverage it — perhaps ironically — using feature detection!&lt;/p&gt;
&lt;p&gt;To suppress the old school user agent check, we can look at &lt;code&gt;navigator.userAgentData&lt;/code&gt; first. If it&#39;s present, we can check to see if we&#39;re using a Chromium browser and, if so, stop there. Otherwise, we can do the traditional check.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; isChromium &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; navigator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userAgentData&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;brands&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;some&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;brand&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Chromium&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; isFirefox &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; isChromium &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; navigator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userAgent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Firefox&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that we&#39;re specifically checking for Chromium in &lt;code&gt;navigator.userAgentData.brands&lt;/code&gt; because that&#39;s a known value. It&#39;s not clear if or when Firefox will support &lt;code&gt;navigator.userAgentData&lt;/code&gt; and, when does, what it will provide as a brand. Checking for &lt;code&gt;&amp;quot;Firefox&amp;quot;&lt;/code&gt; seems sensible, but given the &lt;a href=&quot;https://webaim.org/blog/user-agent-string-history/&quot;&gt;strange history of user agent strings&lt;/a&gt;, they could ship something like &lt;code&gt;&amp;quot;Gecko&amp;quot;&lt;/code&gt; or &lt;code&gt;&amp;quot;Quantum&amp;quot;&lt;/code&gt; instead.&lt;/p&gt;
&lt;p&gt;Or, devastatingly, they could ship &lt;code&gt;&amp;quot;Chromium&amp;quot;&lt;/code&gt; for some kind of compatibility reason. If they do that, well, this check will blow up.*&lt;/p&gt;
&lt;p&gt;So yeah, turns out browser sniffing really does stink.&lt;/p&gt;
&lt;h2 id=&quot;browser-sniffing-stinks%2C-but-it&#39;s-sometimes-necessary&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/not-everything-can-be-feature-detected/#browser-sniffing-stinks%2C-but-it&#39;s-sometimes-necessary&quot;&gt;Browser Sniffing Stinks, But It&#39;s Sometimes Necessary&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Clearly, user agent sniffing is unreliable, so there&#39;s good reason to avoid it. But if we commit to never ever doing it, there will inevitably be some problems we can&#39;t solve.&lt;/p&gt;
&lt;p&gt;So when is it OK to do naughty things? Typically as a last resort after all other options have been exhausted. In the Shoelace example above, no functionality is lost if the check fails. Instead, the user will simply see two clear buttons. That&#39;s not ideal, but it&#39;s also not broken.&lt;/p&gt;
&lt;p&gt;That&#39;s a good rule of thumb. If you absolutely can&#39;t feature detect something and you can implement a sniff that, when it fails, won&#39;t lead to a loss of functionality, go ahead and sniff that browser.&lt;/p&gt;
&lt;hr /&gt;
&lt;small&gt;
&lt;p&gt;*In this case, it seems unlikely Firefox would bloat the new &lt;code&gt;navigator.userAgentData&lt;/code&gt; API with the wrong user agent. After all, the new API doesn&#39;t have all the crazy history that &lt;code&gt;navigator.userAgent&lt;/code&gt; has, but we know better than to make such assumptions on the Web.&lt;/p&gt;
&lt;/small&gt;
</content>
	</entry>
	
	<entry>
		<title>Buttons and Cursors</title>
		<link href="https://www.abeautifulsite.net/posts/buttons-and-cursors/"/>
		<updated>2022-07-27T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/buttons-and-cursors/</id>
		<content type="html">&lt;p&gt;There&#39;s a post from 2016 entitled &lt;a href=&quot;https://medium.com/simple-human/buttons-shouldnt-have-a-hand-cursor-b11e99ca374b&quot;&gt;Buttons shouldn&#39;t have a hand cursor&lt;/a&gt; that&#39;s been making its way around social media this week. While the author is correct in his statement that operating system buttons don&#39;t have hand cursors, the pattern has become ubiquitous and somewhat expected on the Web.&lt;/p&gt;
&lt;p&gt;Some of his points include:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When a button has the hand cursor, it subtly suggests that the user is interacting with a link when they’re not.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The hand cursor is reserved for links. This is because they are unique in their behaviour.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Links have always been handled this way since the web came along — this is the convention of the web that you need not innovate on.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Admittedly, most of my designs as of late &lt;em&gt;do&lt;/em&gt; include &lt;code&gt;cursor: pointer&lt;/code&gt; for buttons as well as other clickable, non-link controls. And while I don&#39;t have a strong opinion either way, revisiting that post triggered a thought about the psychology behind user interfaces.&lt;/p&gt;
&lt;h2 id=&quot;learned-behaviors&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/buttons-and-cursors/#learned-behaviors&quot;&gt;Learned Behaviors&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As a computer user, you undoubtedly know what radio buttons are and how they work. But &lt;em&gt;how&lt;/em&gt; do you know that? Do you remember the very first time you used one? Probably not, but it&#39;s likely that your first experience created a pathway in your brain that said &amp;quot;I can only pick &lt;em&gt;one&lt;/em&gt; of these&amp;quot; and that knowledge has been engrained ever since.&lt;/p&gt;
&lt;p&gt;These are &lt;em&gt;learned behaviors&lt;/em&gt;. A child who has never seen a radio button before might try to click on one to make a choice. Then they might click on another one to select a second choice. Quickly, the child will realize the limitations of a radio button: &amp;quot;I can only pick one.&amp;quot;&lt;/p&gt;
&lt;p&gt;That lesson remains with them until something challenges the pattern, and when such change occurs, they will dislike it because it doesn&#39;t feel correct to them. It&#39;s suddenly &amp;quot;unintuitive&amp;quot; because they&#39;ve learned to expect certain behaviors, and anything unfamiliar will be called out as &amp;quot;poor design.&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/inverted-radio-checkbox-shapes.png&quot; alt=&quot;Screenshot of a square radio and circular checkbox — wait, what?!&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This is why radio buttons are almost always round and checkboxes are almost always square. Swapping something as simple as the shape of these controls will confuse users because it contradicts their learned behaviors.&lt;/p&gt;
&lt;h2 id=&quot;how-we-got-here&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/buttons-and-cursors/#how-we-got-here&quot;&gt;How We Got Here&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If users develop such intrinsic expectations for consistent UIs, then how did the proliferation of hand cursors on buttons even occur? A theory I have dates back to the &amp;quot;Web 2.0&amp;quot; trend where buttons got bigger, more colorful, and eventually a lot flatter. When buttons stopped looking like buttons, designers threw in a subtle way to more easily distinguish them by changing the cursor.&lt;/p&gt;
&lt;p&gt;Plenty of users complained about flat design, but I believe the trend is directly related to why almost every button on the Web today has a &amp;quot;link cursor.&amp;quot; It was a subtle enough change — an improvement, if you will — that made flatter controls more tolerable. Web designers slipped the pattern in and, while everyone was busy complaining about the lack of skeuomorphism and increasingly harder-to-identify buttons, nobody really noticed.&lt;/p&gt;
&lt;p&gt;Now that nearly every clickable thing on the web seems to have a hand cursor, I&#39;d argue that &lt;em&gt;not&lt;/em&gt; doing it is the new anti-pattern, largely due to user expectations. The Web isn&#39;t an operating system and, despite the obvious inconsistency between operating system and Web interfaces, nobody seems to care.*&lt;/p&gt;
&lt;p&gt;In some ways, I wonder if this hurts the web. Those of us who would love to see Web-based technologies compete more with native apps could easily argue that Web apps should behave the same way to make them as indistinguishable as possible, but I seldom hear about this particular inconsistency in the wild.&lt;/p&gt;
&lt;p&gt;I wonder if anyone would even notice if we suddenly removed the hand cursor from all of our buttons. My guess is that few would, especially now that touch devices are more prominent for consumers. The handful of people who &lt;em&gt;would&lt;/em&gt; notice are those that &lt;em&gt;aren&#39;t&lt;/em&gt; browsing on iPhones and iPads, but &amp;quot;regular&amp;quot; computer users who, arguably, aren&#39;t so regular anymore.&lt;/p&gt;
&lt;hr /&gt;
&lt;small&gt;
&lt;p&gt;*Admittedly, I don&#39;t have a strong preference here. I rarely think about it, although the thought does cross my mind from time to time. I tend to side with my users&#39; expectations and, given the ubiquity of hand cursors on the Web, I&#39;ll continue to change the cursor on buttons until there&#39;s a good reason to stop.&lt;/p&gt;
&lt;/small&gt;
</content>
	</entry>
	
	<entry>
		<title>My Stance on AI-generated Code</title>
		<link href="https://www.abeautifulsite.net/posts/my-stance-on-ai-generated-code/"/>
		<updated>2022-07-08T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/my-stance-on-ai-generated-code/</id>
		<content type="html">&lt;p&gt;&lt;strong&gt;2026-04-20&lt;/strong&gt; - Times change, and so do feelings. &lt;a href=&quot;https://www.abeautifulsite.net/posts/my-stance-on-ai-in-software-development/&quot;&gt;Please see this post&lt;/a&gt; for my latest thoughts on the matter.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;I recently added this to &lt;a href=&quot;https://shoelace.style/resources/contributing&quot;&gt;Shoelace&#39;s contribution guidelines&lt;/a&gt;, which sums up my position on AI-generated code.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As an open source maintainer, I respectfully ask that you refrain from using AI-generated code when contributing to this project. This includes code generated by tools such as GitHub Copilot, even if you make alterations to it afterwards. While some of Copilot&#39;s features are indeed convenient, the ethics surrounding which codebases the AI has been trained on and their corresponding software licenses remain very questionable and have yet to be tested in a legal context.&lt;/p&gt;
&lt;p&gt;I realize that one cannot reasonably enforce this any more than one can enforce not copying licensed code from other codebases, nor do I wish to expend energy policing contributors. I would, however, like to avoid all ethical and legal challenges that result from using AI-generated code. As such, I respectfully ask that you refrain from using such tools when contributing to this project. At this time, I will not knowingly accept any code that has been generated in such a manner.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Also let it be known that I would have zero problem with people using Copilot et al if software licensing and attribution were respected. But it means nothing if a computer &amp;quot;learns&amp;quot; from licensed and copyrighted code and spits it back out in your project like it&#39;s your own.&lt;/p&gt;
&lt;p&gt;As humans, we learn from each other&#39;s code and we produce new code based off those learnings.&lt;/p&gt;
&lt;p&gt;&amp;quot;What&#39;s the difference then?&amp;quot;&lt;/p&gt;
&lt;p&gt;The difference is that humans can&#39;t store copies of every available codebase in their brain. We remember concepts. Computers remember by copying.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Design Systems Aren&#39;t Cheap</title>
		<link href="https://www.abeautifulsite.net/posts/design-systems-arent-cheap/"/>
		<updated>2022-03-21T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/design-systems-arent-cheap/</id>
		<content type="html">&lt;p&gt;Buttons are one of my favorite components. On the surface they seem simple, but in practice, they tend to be much more involved. In a post by Nathan Curtis entitled &lt;a href=&quot;https://medium.com/eightshapes-llc/and-you-thought-buttons-were-easy-26eb5b5c1871&quot;&gt;And you thought buttons were easy?&lt;/a&gt;, he demonstrates how costs can quickly skyrocket to $1,000,000 when one arm of the organization isn&#39;t aware of what the other is doing.&lt;/p&gt;
&lt;p&gt;This is easy to brush off as an extreme example that only applies to really large companies. But how much does a design system actually cost?&lt;/p&gt;
&lt;h2 id=&quot;a-real-life-example&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/design-systems-arent-cheap/#a-real-life-example&quot;&gt;A Real Life Example&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before joining Microsoft, I did a short stint at a company with more than 10,000 employees. I was on a dedicated design system team that included five engineers, four designers, and two design technologists. Over the course of 12 months, they had built about 30 components for their design system.&lt;/p&gt;
&lt;p&gt;Many of those positions paid six figure salaries, and that doesn&#39;t account for benefits and HR costs. Let&#39;s pretend the average salary for each position was only $100K USD. That&#39;s 11 &lt;abbr title=&quot;Full Time Employees&quot;&gt;FTEs&lt;/abbr&gt; working for a year, &lt;em&gt;totaling $1.1M in salaries&lt;/em&gt;. Again, this doesn&#39;t include stock grants, health insurance, and additional benefits.&lt;/p&gt;
&lt;p&gt;All that to build buttons, dialogs, form controls, tabs — nothing proprietary. Just every day components that have been built many, many times before.&lt;/p&gt;
&lt;h2 id=&quot;the-cost-of-frameworks&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/design-systems-arent-cheap/#the-cost-of-frameworks&quot;&gt;The Cost of Frameworks&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I forgot to mention that the components they were building were for React, which means that only React teams can use them. As a result, either the entire company must agree to use React or non-React teams will have to duplicate effort by building the same thing in &lt;em&gt;their&lt;/em&gt; framework, running the price up even higher.&lt;/p&gt;
&lt;p&gt;In large orgs, these costs tend to fly under the radar, but they&#39;re tangible expenses if you know where to look.&lt;/p&gt;
&lt;p&gt;Many design system teams I&#39;ve spoken with are rebuilding or preparing to rebuild &amp;quot;legacy&amp;quot; design systems. The story usually goes something like &amp;quot;we&#39;re phasing out Angular 1.x&amp;quot; or &amp;quot;we&#39;re evolving from a Bootstrap-like design system.&amp;quot;&lt;/p&gt;
&lt;p&gt;And a lot of them want to build in React.&lt;/p&gt;
&lt;p&gt;This leads to more costs that aren&#39;t being realized. Just like jQuery dominated the front end yesterday, React dominates it today. There will be something new that dominates it tomorrow. Your design system team will continue doing the same work and incurring more and more costs to keep up with framework churn. And let&#39;s not forget the cost of updating tomorrow&#39;s legacy apps, who are consumers of your soon to be legacy design system.&lt;/p&gt;
&lt;h2 id=&quot;the-platform-outlives-frameworks&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/design-systems-arent-cheap/#the-platform-outlives-frameworks&quot;&gt;The Platform Outlives Frameworks&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A modern design system&#39;s component library — the foundational elements from which all your apps are built — are excellent candidates for &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Web_Components&quot;&gt;Web Components&lt;/a&gt;: a standard technology that&#39;s built into all modern browsers. Web components are used by &lt;a href=&quot;https://arewebcomponentsathingyet.com/&quot;&gt;some of the world&#39;s largest companies&lt;/a&gt;, including Adobe, Amazon, Apple, Ford, GM, Google, Microsoft, NASA, Salesforce, SpaceX, Visa, and many, many more.*&lt;/p&gt;
&lt;p&gt;If you care about longevity and cost, the platform is simply a more logical choice because browsers have committed to supporting Web Components for a long time.&lt;/p&gt;
&lt;p&gt;It&#39;s astonishing to me that so many engineers fail to see that doing the same work over and over again isn&#39;t productive nor cost effective. How many times do you have to rebuild a button before you think &amp;quot;maybe this isn&#39;t the best way forward?&amp;quot; Imagine how much more productive an organization could be if those design and engineering hours were spent elsewhere.&lt;/p&gt;
&lt;p&gt;Now imagine if you didn&#39;t have to build all those portable UI primitives yourself. What if you could just apply some of your own styles and start building patterns and apps? 🤔&lt;/p&gt;
&lt;h2 id=&quot;jump-starting-your-design-system&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/design-systems-arent-cheap/#jump-starting-your-design-system&quot;&gt;Jump Starting Your Design System&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Every design system is different, but how much would you save if you could kick things off with a solid set of accessible, well-tested components? Imagine &lt;em&gt;not&lt;/em&gt; spending $1,000,000 on buttons. Imagine jumping right in and building more useful components for your organization. Imagine telling your engineers to use whatever framework they want because it will work just fine with your design system.&lt;/p&gt;
&lt;p&gt;That&#39;s one of the reasons I built &lt;a href=&quot;https://shoelace.style/&quot;&gt;Shoelace&lt;/a&gt;, an open source web component library that serves as a design system starter kit.**&lt;/p&gt;
&lt;p&gt;Shoelace solves real world problems by offering accessible, intuitive, and interoperable components that save teams and individuals tens of thousands of dollars or more. It&#39;s totally free, by the way, although &lt;a href=&quot;https://github.com/sponsors/claviska&quot;&gt;sponsorships are always welcome&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There&#39;s no need to roll your own buttons anymore.&lt;/p&gt;
&lt;hr /&gt;
&lt;small&gt;
&lt;p&gt;*There&#39;s a longstanding misconception that Web Components aren&#39;t ready for mainstream consumption. This is a stale argument that held more water many years ago when the standards were less mature. These days, companies such as Adobe are embracing Web Standards by &lt;a href=&quot;https://web.dev/ps-on-the-web/&quot;&gt;migrating flagship products to web components&lt;/a&gt;. Web components aren&#39;t just ready for mainstream — they &lt;em&gt;are&lt;/em&gt; mainstream.&lt;/p&gt;
&lt;p&gt;**One of my followers told me they didn&#39;t want to use a third-party library as a basis for their design system. I suggested they fork the project if they want to have complete control of it. Their reply was something like, &amp;quot;but then I have to maintain it myself!&amp;quot; That argument wasn&#39;t well thought out, because you&#39;ll still be maintaining it yourself if you build it from scratch!&lt;/p&gt;
&lt;/small&gt;
</content>
	</entry>
	
	<entry>
		<title>CSS Parts Inspired by BEM</title>
		<link href="https://www.abeautifulsite.net/posts/css-parts-inspired-by-bem/"/>
		<updated>2022-03-10T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/css-parts-inspired-by-bem/</id>
		<content type="html">&lt;p&gt;In a previous post, &lt;a href=&quot;https://www.abeautifulsite.net/posts/valid-names-for-css-parts/&quot;&gt;I explored valid names for CSS parts&lt;/a&gt; and discovered that there are very few restrictions in what you can call them. The purpose of that deep dive was to help identify a pattern for naming parts that lets me expose states and &lt;em&gt;subparts&lt;/em&gt;, or parts exported as a result of composition.&lt;/p&gt;
&lt;p&gt;Using inspiration from &lt;a href=&quot;http://getbem.com/&quot;&gt;BEM&lt;/a&gt;, I&#39;ve settled on a familiar and intuitive pattern that I&#39;d like to share.&lt;/p&gt;
&lt;h2 id=&quot;blocks-%E2%86%92-parts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/css-parts-inspired-by-bem/#blocks-%E2%86%92-parts&quot;&gt;Blocks → Parts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In BEM terms, a &lt;em&gt;block&lt;/em&gt; &amp;quot;encapsulates a standalone entity that is meaningful on its own.&amp;quot; Block names consist only of Latin letters, numbers, and dashes. This translates well to CSS parts.&lt;/p&gt;
&lt;p&gt;Consider the following custom element template. It&#39;s contrived, as its only purpose is to render an image.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- shadow root --&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;part&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we wanted to make a more descriptive name, we could have called the part &lt;code&gt;user-provided-image&lt;/code&gt; or something, as long as we stick to letters, numbers, and dashes.&lt;/p&gt;
&lt;h2 id=&quot;elements-%E2%86%92-subparts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/css-parts-inspired-by-bem/#elements-%E2%86%92-subparts&quot;&gt;Elements → Subparts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In BEM, &lt;em&gt;elements&lt;/em&gt; are &amp;quot;parts of a block [that] have no standalone meaning. Any element is semantically tied to its block.&amp;quot; An example looks like this.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;block&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  ...
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;block__elem&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note the two underscores separating the block from the element. You might be wondering how this ties into CSS parts. Since parts are unique to the shadow root, we don&#39;t need to namespace them to prevent collisions. Two different custom elements can have two different parts with the same name and that&#39;s totally fine.&lt;/p&gt;
&lt;p&gt;However, when a custom element is nested inside another custom element, it&#39;s often desirable to expose the nested element &lt;em&gt;and&lt;/em&gt; its parts, otherwise, consumers won&#39;t be able to target it fully with &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/::part&quot;&gt;&lt;code&gt;::part()&lt;/code&gt;&lt;/a&gt;.* This means we need to expose the nested element with the &lt;a href=&quot;https://www.w3.org/TR/css-shadow-parts-1/#part-attr&quot;&gt;&lt;code&gt;part&lt;/code&gt;&lt;/a&gt; attribute and its parts with the &lt;a href=&quot;https://www.w3.org/TR/css-shadow-parts-1/#exportparts-attr&quot;&gt;&lt;code&gt;exportparts&lt;/code&gt;&lt;/a&gt; attribute.&lt;/p&gt;
&lt;p&gt;Let&#39;s evolve our example so it contains a nested a custom element called &lt;code&gt;&amp;lt;my-image&amp;gt;&lt;/code&gt;, and let&#39;s assume that &lt;code&gt;&amp;lt;my-image&amp;gt;&lt;/code&gt; has two parts called &lt;code&gt;photo&lt;/code&gt; and &lt;code&gt;caption&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- shadow root --&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;my-image&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;part&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;exportparts&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;
      photo:image__photo,
      caption:image__caption
    &lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    ...
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;my-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can see that I&#39;ve exposed the host element for styling with &lt;code&gt;part=&amp;quot;image&amp;quot;&lt;/code&gt;, which follows the &amp;quot;block&amp;quot; naming convention. Now take a look at the &lt;code&gt;exportparts&lt;/code&gt; attribute. Conveniently, we can rename subparts when we export them. This lets us avoid collisions (e.g. what if the host element and the nested element have parts of the same name?).&lt;/p&gt;
&lt;p&gt;In this example, the host element is exposed through the &lt;code&gt;image&lt;/code&gt; part, and its &lt;code&gt;photo&lt;/code&gt; and &lt;code&gt;caption&lt;/code&gt; subparts are exposed as &lt;code&gt;image__photo&lt;/code&gt; and &lt;code&gt;image__caption&lt;/code&gt;, respectively. Notice how everything is scoped to the &lt;code&gt;image&lt;/code&gt; block now?&lt;/p&gt;
&lt;p&gt;End users can now use a very familiar syntax for targeting the nested element and all its parts in their CSS.&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;::part(image)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* matches the nested &amp;lt;my-image&gt; element */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;::part(image__photo)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* matches the subpart named photo in &amp;lt;my-image&gt; */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;::part(image__caption)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* matches the subpart named caption in &amp;lt;my-image&gt; */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&#39;s not uncommon for custom element authors to neglect to export parts. At the time of this writing, &lt;code&gt;exportparts&lt;/code&gt; seems to be one of the lesser known features of web components, but &lt;a href=&quot;https://caniuse.com/mdn-html_global_attributes_exportparts&quot;&gt;it&#39;s well-supported&lt;/a&gt; and incredibly powerful.&lt;/p&gt;
&lt;p&gt;Anyways, this is feeling pretty good so far!&lt;/p&gt;
&lt;h2 id=&quot;modifiers-%E2%86%92-states&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/css-parts-inspired-by-bem/#modifiers-%E2%86%92-states&quot;&gt;Modifiers → States&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Element state is a pretty simple concept. If you have a button, it can have a hover state, a focus state, an active state, etc. Normally, we can target such states with CSS using pseudo selectors.&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;button:hover&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* targets the button&#39;s hover state */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This also works with parts, too.&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;::part(image):hover&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* targets the image part&#39;s hover state */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But not all states are available to target with pseudo selectors, and what if you want to add custom states? More often than not, custom element authors lean on host element attributes for this.&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;my-image[loaded]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* targets the host element when the image has loaded successfully */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;my-image[error]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* targets the host element when the image fails to load */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While this works, mapping stateful parts to attributes on the host element isn&#39;t an elegant solution. Let&#39;s see how we can improve our example using stateful parts and a BEM-like syntax. In BEM, a &lt;em&gt;modifier&lt;/em&gt; is used &amp;quot;to change appearance, behavior or state&amp;quot; and is delimited by two dashes.&lt;/p&gt;
&lt;p&gt;Fortunately, parts are designed to work a lot like classes. In fact, they use the same &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList&quot;&gt;DOMTokenList&lt;/a&gt; API as &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element/classList&quot;&gt;&lt;code&gt;classList&lt;/code&gt;&lt;/a&gt;. This means elements can have more than one part, and part names can be reused throughout the custom element&#39;s template!&lt;/p&gt;
&lt;p&gt;Evolving our example further, we can add modifier parts to indicate various states. Let&#39;s imagine the image in our example has loaded successfully. We can indicate this by adding the &lt;code&gt;image--loaded&lt;/code&gt; part.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- shadow root --&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;my-image&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;part&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image image--loaded&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;exportparts&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    ...
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;my-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can target the loaded state using &lt;code&gt;::part()&lt;/code&gt;!&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;::part(image--loaded)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* targets the image once it has loaded */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There&#39;s no limit to the number of parts an element can have. You can add many additional states if you think they&#39;ll be useful.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- shadow root --&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;my-image&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;part&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;
      image
      image--loaded
      image--square
      image--large
      image--jpeg
    &lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;exportparts&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    ...
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;my-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;why-bem%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/css-parts-inspired-by-bem/#why-bem%3F&quot;&gt;Why BEM?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While the examples herein are contrived, I&#39;m hoping you can see the value in using the BEM convention for naming CSS parts. I chose it because it&#39;s familiar and it easily represents everything we need: parts, subparts, and states.&lt;/p&gt;
&lt;p&gt;Another big win for BEM-inspired part names is that consumers don&#39;t have to escape anything in their CSS. It&#39;s perfectly valid to name a part &lt;code&gt;image:loaded&lt;/code&gt;, for example.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;part&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image image:loaded&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But your users will need to escape the colon in their stylesheet, otherwise the selector won&#39;t match.&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;::part(image&#92;:loaded)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* this works, but requires a backslash before the colon */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This may not seem like a big deal but, in the world of CSS, escaping isn&#39;t something users typically do and they&#39;re probably going to forget. Imagine how frustrating it will be for a user to see a part called &lt;code&gt;image:loaded&lt;/code&gt; in your documentation and, when they try to implement it, it doesn&#39;t work and they don&#39;t know why.&lt;/p&gt;
&lt;p&gt;Since dashes and underscores don&#39;t need to be escaped, they&#39;re a more foolproof choice for naming parts.&lt;/p&gt;
&lt;hr /&gt;
&lt;small&gt;
&lt;p&gt;*The &lt;code&gt;::part()&lt;/code&gt; selector is &lt;a href=&quot;https://www.w3.org/TR/css-shadow-parts-1/#selectordef-part&quot;&gt;intentionally limited&lt;/a&gt; by the spec so you can only target elements the custom element author explicitly exposes.&lt;/p&gt;
&lt;/small&gt;
</content>
	</entry>
	
	<entry>
		<title>When To Create CSS Parts</title>
		<link href="https://www.abeautifulsite.net/posts/when-to-create-css-parts/"/>
		<updated>2022-02-21T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/when-to-create-css-parts/</id>
		<content type="html">&lt;p&gt;I was recently asked a really good question on Twitter: &lt;a href=&quot;https://twitter.com/markacianfrani/status/1479531196971421702&quot;&gt;when shouldn&#39;t an element be a CSS Part?&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I&#39;ve spent a lot of time building web components, most of which are intended for design systems, and my answer is pretty straight-forward.&lt;/p&gt;
&lt;p&gt;Every part you expose is an API that you&#39;re committing to supporting, so it should be very intentional. Consider a component that uses a complex structure that you later need to refactor. If you&#39;ve exposed everything as a part, your internals are locked down and breaking changes will be harder to avoid.&lt;/p&gt;
&lt;p&gt;We&#39;re in a transitionary period where developers are starting to consume custom elements, many for the first time, and the concept of a shadow DOM frustrates them because they can&#39;t style things the way they&#39;re used to.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;That&#39;s the feature.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You don&#39;t have to worry about internals. All the customizations are built in and exposed through attributes, custom properties, and CSS parts. I think of it &lt;em&gt;not&lt;/em&gt; as a flat chunk of HTML I&#39;m adding to the page, but as unique components with APIs that control their appearances and behaviors.&lt;/p&gt;
&lt;h2 id=&quot;we-as-developers&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/when-to-create-css-parts/#we-as-developers&quot;&gt;We As Developers&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I often hear developers lament, &amp;quot;but I just want to style [some simple thing]!&amp;quot; This is a valid frustration if the custom element isn&#39;t designed well. You can easily run into things that aren&#39;t exposed that probably should be!&lt;/p&gt;
&lt;p&gt;It means we, as custom element authors, must think more about our component APIs. We need to consider composition, portability, and reusability. We can&#39;t just throw some HTML and CSS together and call it done. We have be more intentional with the things we create.&lt;/p&gt;
&lt;p&gt;I don&#39;t think that&#39;s a bad thing. The Web has always been a sort of wild west where anything goes. HTML and CSS, by design, are very forgiving. But when you&#39;re creating components — building blocks that serve as critical pieces of an application&#39;s foundation — you really &lt;em&gt;need&lt;/em&gt; to think them through.&lt;/p&gt;
&lt;p&gt;Think of this as a feature, not a limitation. Be very explicit with the things you expose. Think of CSS parts and custom properties as part of your component&#39;s public API, because that&#39;s exactly what they are.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Valid Names for CSS Parts</title>
		<link href="https://www.abeautifulsite.net/posts/valid-names-for-css-parts/"/>
		<updated>2022-02-20T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/valid-names-for-css-parts/</id>
		<content type="html">&lt;p&gt;&lt;a href=&quot;https://www.w3.org/TR/css-shadow-parts-1/&quot;&gt;CSS Shadow Parts&lt;/a&gt;, colloquially known as &lt;em&gt;CSS Parts&lt;/em&gt;, are used to expose elements inside a web component&#39;s shadow root so they can be styled by consumers with CSS. But what are we allowed to call these parts? What characters comprise a valid CSS part name? To find out, I had to &lt;a href=&quot;https://www.w3.org/TR/css-shadow-parts-1/#element-attrdef-html-global-part&quot;&gt;dive into the spec&lt;/a&gt;!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The part attribute is parsed as a space-separated list of tokens representing the part names of this element.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;OK, but what exactly is a &amp;quot;token?&amp;quot; It&#39;s not really clear from this page, but we get a hint if we look at the spec for the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/::part&quot;&gt;&lt;code&gt;::part()&lt;/code&gt; pseudo selector&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;::part() = ::part( &amp;lt;ident&amp;gt; )
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It expects an &lt;code&gt;&amp;lt;ident&amp;gt;&lt;/code&gt;, whatever that is. Fortunately, there&#39;s &lt;a href=&quot;https://www.w3.org/TR/css-values-4/#typedef-ident&quot;&gt;a link to it&lt;/a&gt; that takes us to a page that defines it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;CSS identifiers, generically denoted by &lt;code&gt;&amp;lt;ident&amp;gt;&lt;/code&gt;, consist of a sequence of characters conforming to the &lt;code&gt;&amp;lt;ident-token&amp;gt;&lt;/code&gt; grammar.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Perfect! So part names must conform to the &lt;code&gt;&amp;lt;ident-token&amp;gt;&lt;/code&gt; grammar, but what&#39;s that mean? Let&#39;s follow the link to &lt;a href=&quot;https://www.w3.org/TR/css-syntax-3/#typedef-ident-token&quot;&gt;&lt;code&gt;&amp;lt;ident-token&amp;gt;&lt;/code&gt;&lt;/a&gt; in the spec.&lt;/p&gt;
&lt;p&gt;From that page:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;ident-token&amp;gt;&lt;/code&gt; [...] have a value composed of zero or more code points. Additionally, hash tokens have a type flag set to either &amp;quot;id&amp;quot; or &amp;quot;unrestricted&amp;quot;. The type flag defaults to &amp;quot;unrestricted&amp;quot; if not otherwise set.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That&#39;s not, uh, super helpful. There&#39;s a link around &amp;quot;code points,&amp;quot; so let&#39;s see if that makes it more clear. The link goes to &lt;a href=&quot;https://infra.spec.whatwg.org/#code-point&quot;&gt;this page&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A code point is a Unicode code point and is represented as &amp;quot;U+&amp;quot; followed by four-to-six ASCII upper hex digits, in the range U+0000 to U+10FFFF, inclusive. A code point’s value is its underlying number.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That seems to be a pretty wide range, though. &lt;a href=&quot;https://en.wikipedia.org/wiki/Plane_(Unicode)&quot;&gt;According to Wikipedia:&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The last code point in Unicode is the last code point in plane 16, U+10FFFF.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So does this mean we can use any Unicode character as a CSS part name? I&#39;m no Unicode expert, so it still isn&#39;t clear.&lt;/p&gt;
&lt;h2 id=&quot;experimenting-with-various-characters&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/valid-names-for-css-parts/#experimenting-with-various-characters&quot;&gt;Experimenting with Various Characters&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let&#39;s experiment and see what actually works in the browser. I created a sample custom element with the following parts, then tried styling them with &lt;code&gt;::part()&lt;/code&gt; to see what actually worked.&lt;/p&gt;
&lt;pre class=&quot;language-md&quot;&gt;&lt;code class=&quot;language-md&quot;&gt;✅ part=&quot;a&quot;
✅ part=&quot;a-b&quot;
✅ part=&quot;a_b&quot;
❌ part=&quot;a,b&quot;
❌ part=&quot;a.b&quot;
❌ part=&quot;a$b&quot;
❌ part=&quot;a+b&quot;
❌ part=&quot;a@b&quot;
❌ part=&quot;a?b&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Clearly we can&#39;t use &lt;em&gt;any&lt;/em&gt; character for part names. The browser doesn&#39;t like symbols, which feels intuitive to be honest.&lt;/p&gt;
&lt;p&gt;Let&#39;s try some more characters.&lt;/p&gt;
&lt;pre class=&quot;language-md&quot;&gt;&lt;code class=&quot;language-md&quot;&gt;✅ part=&quot;á&quot;
✅ part=&quot;ñ&quot;
✅ part=&quot;ę&quot;
✅ part=&quot;Ф&quot;
✅ part=&quot;平&quot;
✅ part=&quot;λ&quot;
✅ part=&quot;ה&quot;
✅ part=&quot;字&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It seems to be OK with non-punctuation. What about emojis?!&lt;/p&gt;
&lt;pre class=&quot;language-md&quot;&gt;&lt;code class=&quot;language-md&quot;&gt;✅ part=&quot;🥕&quot;
✅ part=&quot;🐛&quot;
✅ part=&quot;🐓&quot;
✅ part=&quot;💩&quot;
✅ part=&quot;🤨&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Totally fine. So it seems like any character except punctuation is good. Let&#39;s check out that lower Unicode range the spec referred to: U+0000&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.unicode.org/charts/PDF/U0000.pdf&quot;&gt;Here&#39;s a document&lt;/a&gt; with the lower end character points. It lists a number of the symbols we tried earlier in this range. 🥲&lt;/p&gt;
&lt;p&gt;Clearly this range doesn&#39;t reflect valid CSS part names. Maybe we overlooked something in the spec, or maybe the CSS spec defines the argument too generically. Surely &lt;a href=&quot;https://html.spec.whatwg.org/#global-attributes&quot;&gt;the HTML spec&lt;/a&gt; will explain it better.&lt;/p&gt;
&lt;p&gt;Whoops...there&#39;s no mention of the &lt;code&gt;part&lt;/code&gt; attribute at all. 😭&lt;/p&gt;
&lt;p&gt;Let&#39;s see if &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes#attr-part&quot;&gt;this MDN page&lt;/a&gt; can help us clear things up.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A space-separated list of the part names of the element. Part names allows CSS to select and style specific elements in a shadow tree via the ::part pseudo-element.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;OK, but &lt;em&gt;what&lt;/em&gt; is a valid part name?!&lt;/p&gt;
&lt;h2 id=&quot;mdn-to-the-rescue&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/valid-names-for-css-parts/#mdn-to-the-rescue&quot;&gt;MDN To The Rescue&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I&#39;m still not sure what&#39;s correct per the spec. Let&#39;s take a look at &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/::part&quot;&gt;the &lt;code&gt;::part()&lt;/code&gt; docs&lt;/a&gt; in MDN now. I found this, which looks a lot like what we saw in the spec!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;::part( `&amp;lt;ident&amp;gt;+` )
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There&#39;s a link around &lt;code&gt;&amp;lt;ident&amp;gt;&lt;/code&gt; that goes &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/ident&quot;&gt;to this page&lt;/a&gt;, which says:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/ident-mdn.png&quot; alt=&quot;Screenshot from the aforementioned page that shows the definition of &amp;lt;ident&amp;gt;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Thus far, MDN has provided the most human-readable explanation of what a valid ident is, and therefore what a valid CSS part name is. Here&#39;s the rundown of valid characters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A-Z, a-z&lt;/li&gt;
&lt;li&gt;0-9&lt;/li&gt;
&lt;li&gt;hyphens&lt;/li&gt;
&lt;li&gt;underscores&lt;/li&gt;
&lt;li&gt;escaped chars&lt;/li&gt;
&lt;li&gt;unicode chars in hex format&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This explains why my punctuation examples didn&#39;t work. Here&#39;s something interesting, though:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;an escaped character (preceded by a backslash, )&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So &lt;em&gt;can&lt;/em&gt; we use any character? Let&#39;s try one of those parts with punctuation that didn&#39;t work again:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;part&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;a.b&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now let&#39;s target it with CSS:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;::part(a&#92;.b)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  ...
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It works! So the spec is technically correct in that any character can be used, it just wasn&#39;t clear in that some of them need to be escaped.&lt;/p&gt;
&lt;p&gt;Check this out:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;part&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;a.b{c}|d&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And with CSS:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;::part(a&#92;.b&#92;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;c&#92;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token selector&quot;&gt;&#92;|d)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  ...
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works too!&lt;/p&gt;
&lt;h2 id=&quot;using-parts-to-target-state&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/valid-names-for-css-parts/#using-parts-to-target-state&quot;&gt;Using Parts To Target State&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Until now, I&#39;ve primary used a single part for each element I wanted to expose. However, &lt;a href=&quot;https://drafts.csswg.org/css-shadow-parts/#part&quot;&gt;per the spec&lt;/a&gt;, parts should be used more like classes:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Part names act similarly to classes: multiple elements can have the same part name, and a single element can have multiple part names.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I guess I should change the way I use parts. I used to think of them as an identifier, but thinking of them more like &lt;em&gt;classes&lt;/em&gt; as the spec suggests can help fill a gap!&lt;/p&gt;
&lt;p&gt;Now that I know underscores are valid, I may explore them as a convention for hover/focus/active states since we never got the &lt;code&gt;::state&lt;/code&gt; selector. For example, we can give parts a synthetic focus state or even &amp;quot;hoist&amp;quot; a natural focus state to another element in the component.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;part&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;control control_focus&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this convention, perhaps we don&#39;t need a &lt;code&gt;::state&lt;/code&gt; selector after all!&lt;/p&gt;
&lt;h2 id=&quot;just-because-you-can%2C-doesn&#39;t-mean-you-should&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/valid-names-for-css-parts/#just-because-you-can%2C-doesn&#39;t-mean-you-should&quot;&gt;Just Because You Can, Doesn&#39;t Mean You Should&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So there you have it. You can name CSS parts anything you want — just remember to escape special characters! Using the previous example, we can even remove all of the letters and make a part name with only symbols!&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;part&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;.{}|&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The selector gets a bit crazy, though.&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;::part(&#92;.&#92;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&#92;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token selector&quot;&gt;&#92;|)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* 😎 */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&#39;ve tested this in all modern browsers and it appears to work consistently. Of course, this isn&#39;t very practical. Out of respect for your users, I would advise against naming your CSS parts like this! 🙈&lt;/p&gt;
&lt;p&gt;I&#39;m torn on whether or not special characters are useful here. Perhaps for an internal pattern, but I don&#39;t think I&#39;d expose it as part of a public API. Users will definitely forget to escape those characters in their stylesheets. For my parts, I&#39;ll probably continue using a-z and dashes most of the time.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;This post was originally &lt;a href=&quot;https://x.com/claviska/status/1495430320606359555&quot;&gt;a Twitter thread&lt;/a&gt;.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Complacency on the Front End</title>
		<link href="https://www.abeautifulsite.net/posts/complacency-on-the-front-end/"/>
		<updated>2022-02-14T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/complacency-on-the-front-end/</id>
		<content type="html">&lt;p&gt;We live in a world where front end developers are fatigued from the framework wars. Most have settled into a niche — especially the React crowd — and they’re happy to not have to think outside that box. They are, by far, the hardest crowd to sell web components to.&lt;/p&gt;
&lt;p&gt;I&#39;m not knocking them. They went through hell trying to keep up with things and ended up finding something that made sense and worked for them. Getting shit done is more important than chasing what&#39;s new!&lt;/p&gt;
&lt;p&gt;But it&#39;s time to look up and consider what the platform has to offer &lt;em&gt;nearly 10 years&lt;/em&gt; after React came out.&lt;/p&gt;
&lt;p&gt;Not in a &amp;quot;how can web components replace my framework&amp;quot; way, but in a &amp;quot;how can web components &lt;em&gt;complement&lt;/em&gt; my framework&amp;quot; way.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;This post was &lt;a href=&quot;https://x.com/claviska/status/1493264345865805835?s=20&amp;amp;t=ED80mB9FlqSaVWfTox6leQ&quot;&gt;originally a tweet&lt;/a&gt;.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>A Web Components Primer</title>
		<link href="https://www.abeautifulsite.net/posts/a-web-components-primer/"/>
		<updated>2022-02-04T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/a-web-components-primer/</id>
		<content type="html">&lt;p&gt;On the eve of February, &lt;a href=&quot;https://x.com/claviska/status/1488362221134565380&quot;&gt;I was inspired to tweet about web components&lt;/a&gt;. What started as a simple thought quickly turned into a series of tweets that folks seem to find useful. I&#39;ve adapted the thread and I&#39;m posting it here for prosperity.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;overview&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/a-web-components-primer/#overview&quot;&gt;Overview&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Shadow DOM? Light DOM? Slots? If you&#39;ve heard of these but aren&#39;t sure what they are, maybe this will clear things up!&lt;/p&gt;
&lt;p&gt;Custom elements are a feature that&#39;s baked into modern web browsers. You can build portable, reusable elements and use them in any HTML page. The collection of browser APIs that make this possible is known as &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Web_Components&quot;&gt;web components&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Custom elements are written in JavaScript and must be registered at runtime. A custom element&#39;s tag name must start with a-z and contain at least one dash, e.g. &lt;code&gt;&amp;lt;my-button&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;shadow-dom&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/a-web-components-primer/#shadow-dom&quot;&gt;Shadow DOM&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the best (and least understood) features of web components is the ability to encapsulate styles so nothing leaks in and nothing leaks out. This is done by attaching a hidden, separate DOM to the custom element.&lt;/p&gt;
&lt;p&gt;This hidden DOM is called a &amp;quot;shadow DOM&amp;quot; or &amp;quot;shadow root.&amp;quot;&lt;/p&gt;
&lt;p&gt;The shadow root lets you use simple class names and ids without worrying if other elements on the page are using the same ones. (No more BEM!)&lt;/p&gt;
&lt;p&gt;You can attach styles and scripts to a shadow root, too. It&#39;s kinda like a mini webpage within a webpage…minus the &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt;. 😂&lt;/p&gt;
&lt;h2 id=&quot;the-host-element&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/a-web-components-primer/#the-host-element&quot;&gt;The Host Element&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When you attach a shadow root to a custom element, the custom element acts as the host. Thus, we call it the &amp;quot;host element.&amp;quot; Within a shadow root, you can target the host element in CSS using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/:host%28%29&quot;&gt;&lt;code&gt;:host()&lt;/code&gt;&lt;/a&gt; selector. (OK, it&#39;s technically a function.)&lt;/p&gt;
&lt;p&gt;The host element is just another HTML element, but you control its API. You control what attributes it can have, what properties it uses, and what it renders.&lt;/p&gt;
&lt;p&gt;You can even control the content that gets &amp;quot;slotted in.&amp;quot;&lt;/p&gt;
&lt;h2 id=&quot;slots&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/a-web-components-primer/#slots&quot;&gt;Slots&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Within a shadow root, you can create placeholders called slots. Slots let you control where child elements will be rendered in the template. The default slot looks like this in the custom element&#39;s template:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;slot&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;slot&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Additional slots can be added, but must be named. In the template, that looks like this.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;slot&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;header&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;slot&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Given the following custom element, the default slot will be populated with the paragraph and the &lt;code&gt;header&lt;/code&gt; slot will be populated with the &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;my-element&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;slot&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;header&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Named Slot Example&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Lorem ipsum&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;my-element&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Everything you see here above is rendered in what we call the &amp;quot;light DOM.&amp;quot;&lt;/p&gt;
&lt;h2 id=&quot;light-dom&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/a-web-components-primer/#light-dom&quot;&gt;Light DOM&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You can style things in the light DOM as you&#39;d expect using simple CSS selectors. What you don&#39;t see is the internal HTML structure of the custom element. That stuff exists in the shadow DOM and &lt;em&gt;isn&#39;t&lt;/em&gt; exposed for styling. This is what seems to confuse and frustrate people.&lt;/p&gt;
&lt;p&gt;By default, you can&#39;t style anything other than a few inherited font properties. That doesn&#39;t sound useful at first, but the browser gives us ways to &amp;quot;poke through&amp;quot; the shadow root and apply styles.&lt;/p&gt;
&lt;p&gt;That&#39;s right. As a custom element author, you can tell users what they can and can&#39;t change in the shadow root — and enforce it!&lt;/p&gt;
&lt;p&gt;There are two primary tools we lean on for styling custom elements.&lt;/p&gt;
&lt;h2 id=&quot;css-custom-properties&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/a-web-components-primer/#css-custom-properties&quot;&gt;CSS Custom Properties&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Unlike regular CSS properties, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties&quot;&gt;CSS Custom Properties&lt;/a&gt;, or &amp;quot;CSS variables,&amp;quot; cascade through shadow roots. They look kinda funny because they always start with two dashes.&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;:root&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;--brand-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; blue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Tip: the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/:root&quot;&gt;&lt;code&gt;:root&lt;/code&gt;&lt;/a&gt; selector above targets the &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; element.&lt;/p&gt;
&lt;p&gt;To reference a CSS variable in a stylesheet, we use the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/var()&quot;&gt;&lt;code&gt;var()&lt;/code&gt;&lt;/a&gt; function.&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;:host&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--brand-color&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;CSS variables get interpolated, so the above will be interpreted by the browser as:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;:host&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; blue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But unlike Sass, nothing gets compiled! Thus, if the variable changes at runtime, the browser happily updates everything using it. Did I mention that CSS variables cascade? You can redefine CSS variables in any selector, including pseudos such as &lt;code&gt;:hover&lt;/code&gt; and &lt;code&gt;:focus&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Of course, since we can&#39;t tap into the shadow DOM to style things, the custom element will need to &amp;quot;expose&amp;quot; which CSS variables it accepts as part of its API. This is a bummer, because the custom element author will need to expose a CSS variable for every property and state you might want to target.&lt;/p&gt;
&lt;p&gt;If only we could style specific &lt;em&gt;parts&lt;/em&gt; inside the shadow DOM. 🤔&lt;/p&gt;
&lt;h2 id=&quot;css-parts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/a-web-components-primer/#css-parts&quot;&gt;CSS Parts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Well, we can! A custom element can expose &amp;quot;parts&amp;quot; which are aptly called &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes&quot;&gt;CSS Parts&lt;/a&gt;. Parts are also defined in the custom element&#39;s template, this time through the &lt;code&gt;part&lt;/code&gt; attribute.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;part&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;container&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  ...
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This exposes a part in the shadow root called &lt;code&gt;container&lt;/code&gt; that consumers can target with CSS.&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;my-element::part(container)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;blue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; white&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you can style any property you want on that part, including states such as &lt;code&gt;:hover&lt;/code&gt; and &lt;code&gt;:focus&lt;/code&gt;!&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;my-element::part(container):hover&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;my-element::part(container):focus&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To recap: a CSS variable allows users to customize a single property and a CSS part allows them to customize &lt;em&gt;all properties&lt;/em&gt; on the exposed part. When authoring custom elements, it&#39;s not always clear which one to use and when. The rule of thumb I follow is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When a single value gets reused throughout a component&#39;s styles, a CSS custom property is usually fine&lt;/li&gt;
&lt;li&gt;When you need to expose more than a handful of properties on a single element, a CSS part is usually better&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;%22why-can&#39;t-i-just-style-things-like-normal%3F%22&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/a-web-components-primer/#%22why-can&#39;t-i-just-style-things-like-normal%3F%22&quot;&gt;&amp;quot;Why can&#39;t I just style things like normal?&amp;quot;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;That&#39;s a great question. I&#39;m glad you asked…&lt;/p&gt;
&lt;p&gt;Custom elements give us a way to build complex components with strong API contracts. Component authors can freely refactor internals without changing the public API. That wouldn&#39;t be possible if everything was exposed by default. Most things would be a breaking change. 😭&lt;/p&gt;
&lt;p&gt;Style and logic encapsulation has been the holy grail of web development for a long time. Many solutions have been implemented to fake it, but elements have always been susceptible to leaks. The platform has finally given us a tool to solve this problem, so it&#39;s worth taking the time to learn and understand it. Once you do, I&#39;m certain you&#39;ll embrace it!&lt;/p&gt;
&lt;h2 id=&quot;%22web-components-sound-kinda-complicated!%22&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/a-web-components-primer/#%22web-components-sound-kinda-complicated!%22&quot;&gt;&amp;quot;Web components sound kinda complicated!&amp;quot;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Perhaps at first, but if you know HTML you&#39;re halfway there! Plus, these are &lt;em&gt;standard browser features&lt;/em&gt; and, unlike framework knowledge, learning this stuff will last you a long, long time.&lt;/p&gt;
&lt;p&gt;Think of all the frameworks you&#39;ve learned over the years and no longer use because their popularity declined. The nice thing about web components is that browsers have committed to supporting them for a long time!&lt;/p&gt;
&lt;p&gt;The spec will surely evolve, but the rug won&#39;t be pulled out from under you.&lt;/p&gt;
&lt;h2 id=&quot;%22how-do-you-write-web-components%3F%22&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/a-web-components-primer/#%22how-do-you-write-web-components%3F%22&quot;&gt;&amp;quot;How do you write web components?&amp;quot;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You can write them with plain ol&#39; JavaScript. Or you can use one of the many great component authoring libraries such as &lt;a href=&quot;https://lit.dev/&quot;&gt;Google&#39;s Lit&lt;/a&gt;. React users might like &lt;a href=&quot;https://github.com/matthewp/haunted&quot;&gt;Haunted&lt;/a&gt; for its hook-like syntax. Functional programmers might prefer &lt;a href=&quot;https://hybrids.js.org/&quot;&gt;Hybrids&lt;/a&gt;. There&#39;s also &lt;a href=&quot;https://fast.design/&quot;&gt;Microsoft&#39;s FAST Element&lt;/a&gt; and many others.&lt;/p&gt;
&lt;p&gt;It&#39;s worth mentioning that both &lt;a href=&quot;https://svelte.dev/docs#run-time-custom-element-api&quot;&gt;Svelte&lt;/a&gt; and &lt;a href=&quot;https://v3.vuejs.org/guide/web-components.html#using-custom-elements-in-vue&quot;&gt;Vue&lt;/a&gt; let you generate custom elements too!&lt;/p&gt;
&lt;p&gt;Each library/framework has its own philosophy, but they all generate web components that work in any framework — and in plain ol&#39; HTML pages.&lt;/p&gt;
&lt;p&gt;The beautiful thing about this is you&#39;re not forced into a specific flavor. You can write web components the way &lt;em&gt;you&lt;/em&gt; want to write them without sacrificing interoperability!&lt;/p&gt;
&lt;h2 id=&quot;%22does-anyone-even-use-web-components%3F%22&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/a-web-components-primer/#%22does-anyone-even-use-web-components%3F%22&quot;&gt;&amp;quot;Does anyone even use web components?&amp;quot;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Yes. &lt;a href=&quot;https://arewebcomponentsathingyet.com/&quot;&gt;A lot of big companies are using them&lt;/a&gt; and they&#39;re becoming ubiquitous. Recently, &lt;a href=&quot;https://x.com/claviska/status/1452621707576029194&quot;&gt;over 18% of pages&lt;/a&gt; loaded in Chrome registered at least one web component.&lt;/p&gt;
&lt;p&gt;Fun fact: &lt;a href=&quot;https://web.dev/ps-on-the-web/&quot;&gt;Adobe is using web components&lt;/a&gt; for the web-based version of Photoshop &lt;a href=&quot;https://twitter.com/WestbrookJ/status/1488365582802116610&quot;&gt;and other apps&lt;/a&gt; that used to be desktop-first are transitioning.&lt;/p&gt;
&lt;h2 id=&quot;%22but-i-like-my-react%2Fvue%2Fangular!%22&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/a-web-components-primer/#%22but-i-like-my-react%2Fvue%2Fangular!%22&quot;&gt;&amp;quot;But I like my React/Vue/Angular!&amp;quot;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;That&#39;s cool! I like frameworks too, but I&#39;m tired of rebuilding the same components every couple years. &lt;a href=&quot;https://custom-elements-everywhere.com/&quot;&gt;Most frameworks play nicely with web components&lt;/a&gt;, so you can have your cake and eat it too!&lt;/p&gt;
&lt;p&gt;While most web components work perfectly fine as-is inside various frameworks, there is one notable exception.&lt;/p&gt;
&lt;p&gt;React is super popular but &lt;a href=&quot;https://www.abeautifulsite.net/posts/a-web-components-primer/custom-elements-everywhere.com/#react&quot;&gt;it kinda doesn&#39;t get web components&lt;/a&gt;. What can we do?! No worries, &lt;a href=&quot;https://x.com/claviska/status/1468624872054087680&quot;&gt;React has added experimental support for custom elements&lt;/a&gt; behind a flag. A lot of progress has been made here recently!&lt;/p&gt;
&lt;p&gt;In the meantime, &lt;a href=&quot;https://npmjs.com/package/@lit-labs/react&quot;&gt;you can wrap any custom element for React&lt;/a&gt; with a simple function call. This will generate a real React component that wires things up to the underlying custom element. It&#39;s like magic! (Tip: the utility has Lit in the name, but it works with all custom elements.)&lt;/p&gt;
&lt;h2 id=&quot;how-to-get-started&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/a-web-components-primer/#how-to-get-started&quot;&gt;How to Get Started&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Hopefully you learned something about web components and shadow DOM in this thread! If you haven&#39;t experimented with them yet, why not? It&#39;s worth your time to better understand them. Even if you&#39;re not developing them yet, you&#39;ll likely be using them soon.&lt;/p&gt;
&lt;p&gt;One great way to jump in is by using a library. I happen to be the author of &lt;a href=&quot;https://shoelace.style/&quot;&gt;Shoelace&lt;/a&gt;, an open source web component library featuring more than 50 useful components.&lt;/p&gt;
&lt;p&gt;This is a great way to get started with custom elements and, because it&#39;s open source, you can dive into the code and start learning &lt;em&gt;how&lt;/em&gt; they&#39;re made too!&lt;/p&gt;
&lt;p&gt;Have questions? Want to learn more about web components? &lt;a href=&quot;https://x.com/claviska&quot;&gt;Follow me on Twitter&lt;/a&gt; for more tips, resources, and other web dev stuff!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Success Requires Luck</title>
		<link href="https://www.abeautifulsite.net/posts/success-requires-luck/"/>
		<updated>2022-01-14T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/success-requires-luck/</id>
		<content type="html">&lt;p&gt;I&#39;ve concluded that successful &amp;quot;makers&amp;quot; have one thing in common: &lt;em&gt;luck.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It&#39;s not that strategy and vision don&#39;t play a role in success, but nobody — &lt;em&gt;literally nobody&lt;/em&gt; — can guarantee that a product or service will be successful. Think about some of the major corporations that launched new products, throwing tens of millions of dollars into research, development, and marketing, only to see &lt;a href=&quot;https://www.usatoday.com/story/money/2018/07/11/50-worst-product-flops-of-all-time/36734837/&quot;&gt;their best efforts flop&lt;/a&gt;.*&lt;/p&gt;
&lt;p&gt;Even if you have the right idea and the right strategy, the timing is hard to get right. Too soon and nobody appreciates your genius. Too late and somebody&#39;s already eaten your lunch. There are simply too many variables to account for.&lt;/p&gt;
&lt;p&gt;Is there skill involved in being successful? Of course. Will connections and capital encourage success? Undoubtedly. But we shouldn&#39;t underestimate the one thing that can make or break our every attempt at success, and we shouldn&#39;t feel disenchanted when our attempt to get a piece of the pie fails.&lt;/p&gt;
&lt;p&gt;At the end of the day, success requires luck.&lt;/p&gt;
&lt;p&gt;So every time you see a post from somebody riding the wave of their success, take it with a grain of salt. There may be tidbits of good advice baked in, but it usually lacks context and their advice can just as easily misdirect you from what might make &lt;em&gt;your&lt;/em&gt; attempt successful.&lt;/p&gt;
&lt;p&gt;Then how do you guarantee success? Generally speaking, you can&#39;t.** However, you can increase your odds by following one simple rule. You may have heard your parents tell you this when you were little:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If at first you don&#39;t succeed, try and try again.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The one piece of advice I will leave you with — which is useful both in and out of the business world — is to simply learn from your mistakes.&lt;/p&gt;
&lt;p&gt;Oh, and good luck!&lt;/p&gt;
&lt;hr /&gt;
&lt;small&gt;
&lt;p&gt;*What I like about this post is that it spans many decades and shows how large companies even outside of the tech industry are prone to failure.&lt;/p&gt;
&lt;p&gt;**Bear in mind that success is relative. Large MRRs and big exits sound appealing, but would you consider $10M in the bank a success? Most of you will say &amp;quot;yes,&amp;quot; but what if it comes at the expense of your happiness? Will having a lot of money make you feel successful if, for example, your family falls apart because you devote your life to making it? The definition of success is different for all of us.&lt;/p&gt;
&lt;/small&gt;
</content>
	</entry>
	
	<entry>
		<title>Flash of Undefined Custom Elements (FOUCE)</title>
		<link href="https://www.abeautifulsite.net/posts/flash-of-undefined-custom-elements/"/>
		<updated>2021-12-29T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/flash-of-undefined-custom-elements/</id>
		<content type="html">&lt;p&gt;&lt;strong&gt;Update (December 23, 2024):&lt;/strong&gt; Check out my latest post on this topic: &lt;a href=&quot;https://www.abeautifulsite.net/posts/revisiting-fouce&quot;&gt;Revisiting FOUCE&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Web components are &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry/define&quot;&gt;defined and registered&lt;/a&gt; with JavaScript. Depending on how and when you load the scripts that perform registration, you may see a brief flash of unstyled HTML where your custom elements should be when the page loads. This is not dissimilar to &lt;a href=&quot;https://en.wikipedia.org/wiki/Flash_of_unstyled_content&quot;&gt;FOUC&lt;/a&gt;, which occurs when HTML is displayed before the stylesheet has loaded.&lt;/p&gt;
&lt;p&gt;For reference, here&#39;s an exaggerated example of three custom elements loading at different intervals.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/fouce.gif&quot; alt=&quot;Exaggerated example of FOUCE as custom elements load one by one&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Since the world needs more acronyms, and since one doesn&#39;t seem to exist yet, I&#39;m calling this phenomenon FOUCE (rhymes with &amp;quot;spouse&amp;quot;), which stands for &lt;em&gt;Flash of Undefined Custom Elements&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Fortunately, the browser gives us some tools to mitigate it.&lt;/p&gt;
&lt;h2 id=&quot;the-%3Adefined-selector&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/flash-of-undefined-custom-elements/#the-%3Adefined-selector&quot;&gt;The &lt;code&gt;:defined&lt;/code&gt; selector&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One option is to use the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/:defined&quot;&gt;&lt;code&gt;:defined&lt;/code&gt;&lt;/a&gt; CSS pseudo-class to &amp;quot;hide&amp;quot; custom elements that haven&#39;t been registered yet. You can scope it to specific tags or you can hide all undefined custom elements as shown below.&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;:not(:defined)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;visibility&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; hidden&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As soon as a custom element is registered, it will immediately appear with all of its styles, effectively eliminating FOUCE. Note the use of &lt;code&gt;visibility: hidden&lt;/code&gt; instead of &lt;code&gt;display: none&lt;/code&gt; to reduce shifting as elements are registered.&lt;/p&gt;
&lt;p&gt;The drawback to this approach is that custom elements can potentially appear one by one instead of all at the same time.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/fouce-css-defined.gif&quot; alt=&quot;FOUCE is gone, but elements can appear at random as they are defined&quot; /&gt;&lt;/p&gt;
&lt;p&gt;That&#39;s certainly a lot better, but can we take things a bit further?&lt;/p&gt;
&lt;h2 id=&quot;awaiting-customelements.whendefined()&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/flash-of-undefined-custom-elements/#awaiting-customelements.whendefined()&quot;&gt;Awaiting &lt;code&gt;customElements.whenDefined()&lt;/code&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Another option is to use &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry/whenDefined&quot;&gt;&lt;code&gt;customElements.whenDefined()&lt;/code&gt;&lt;/a&gt;, which returns a promise that resolves when the specified element gets registered. You&#39;ll probably want to use it with &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled&quot;&gt;&lt;code&gt;Promise.allSettled()&lt;/code&gt;&lt;/a&gt; in case an element fails to load for some reason (&lt;a href=&quot;https://twitter.com/WestbrookJ/status/1476286720278683650?s=20&quot;&gt;thanks, Westbrook!&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;A clever way to use this method is to hide the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; with &lt;code&gt;opacity: 0&lt;/code&gt; and add a class that fades it in as soon as all your custom elements are defined.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;
  &lt;span class=&quot;token selector&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token selector&quot;&gt;body.ready&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;transition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; .25s opacity&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;module&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;allSettled&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    customElements&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;whenDefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;my-button&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    customElements&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;whenDefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;my-card&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    customElements&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;whenDefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;my-rating&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Button, card, and rating are registered now! Add&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// the `ready` class so the UI fades in.&lt;/span&gt;
  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;classList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;ready&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In my opinion, this is the better approach because it subtly fades in the entire page as soon as all your custom elements are registered. After all, what&#39;s the point of showing the page before it&#39;s ready?&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/fouce-whendefined.gif&quot; alt=&quot;No more FOUCE because the body fades in only after all elements are defined&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The drawback, of course, is that you need to keep track of which elements you&#39;re using and add them to the list. But this can also be an advantage if your initial UI only requires a handful of custom elements. For example, you can load only the ones you need upfront and let the rest of them load asynchronously to make your page load faster.&lt;/p&gt;
&lt;hr /&gt;
&lt;small&gt;
  December 30, 2021: The original version of this article mentioned script placement in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; as a method of eliminating FOUCE, but that doesn&#39;t work if you&#39;re using ES modules. While the approach works for non-modules, I&#39;ve removed it because it leads to poor page load times and because of the growing ubiquity of ES modules on the Web.
&lt;/small&gt;
</content>
	</entry>
	
	<entry>
		<title>Bulletproof Components</title>
		<link href="https://www.abeautifulsite.net/posts/bulletproof-components/"/>
		<updated>2021-12-08T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/bulletproof-components/</id>
		<content type="html">&lt;p&gt;Somewhere buried in my dusty basement lives a signed copy of Dan Cederholm&#39;s classic book &lt;a href=&quot;https://simplebits.com/pages/books&quot;&gt;Bulletproof Web Design&lt;/a&gt;. I purchased it during &lt;a href=&quot;https://www.abeautifulsite.net/posts/an-event-apart-boston/&quot;&gt;my first trip to An Event Apart&lt;/a&gt; in 2007. This book meant a lot to me back then, and almost 15 years later, many of its concepts still hold true.&lt;/p&gt;
&lt;p&gt;The premise of the book is that designs should be &amp;quot;bulletproof&amp;quot; to accommodate the many ways they can be used.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I&#39;m using the term &lt;em&gt;bulletproof&lt;/em&gt; partly to describe flexibility — in other words, designs for the web that can easily accommodate various text sizes and amounts of content, designs that expand or contract along with whatever is placed within them.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I&#39;ve been a software engineer for many years. More recently, my focus has been on building design systems. Although a lot has changed on the World Wide Web over the last decade, it&#39;s easy to recognize that many of the principles in Dan&#39;s book also apply to component development.&lt;/p&gt;
&lt;p&gt;But what does a &lt;em&gt;bulletproof component&lt;/em&gt; entail? Before jumping in, let&#39;s take a look at why we break down websites and applications into components in the first place.&lt;/p&gt;
&lt;h2 id=&quot;why-do-we-build-components%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/bulletproof-components/#why-do-we-build-components%3F&quot;&gt;Why do we build components?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Perhaps the most obvious benefit of the component pattern is reusability. Nobody wants to write the same code over and over again. If you end up doing that, have fun finding and updating all of the instances — and variations thereof — that make their way into the wild. This doesn&#39;t scale well in small orgs and it falls flat on its face in large ones.&lt;/p&gt;
&lt;p&gt;Components are a vehicle for reusability. Their very nature leads to visual and behavioral consistency. By encapsulating structure, style, and logic into neat little packages, components become powerful tools in your users&#39; arsenal — tools that are convenient to use and a bit harder to misuse.&lt;/p&gt;
&lt;p&gt;When you break a design down into reusable bits, you can assemble, or &lt;em&gt;compose&lt;/em&gt;, those bits to recreate the original design. Better yet, you can create entirely new designs with a lot less effort. Components are the building blocks of your application!&lt;/p&gt;
&lt;p&gt;It&#39;s no secret that I&#39;m a fan of web components (and &lt;a href=&quot;https://x.com/claviska/status/1466770483739832320&quot;&gt;I&#39;m in good company&lt;/a&gt;), but I&#39;m not here to sell you on web components today. What I will say is that more and more large organizations are leaning on web standards to build and rebuild their design systems in a technology agnostic way. Interoperability falls under the umbrella of reusability, but I think it&#39;s an important technical detail to point out.&lt;/p&gt;
&lt;h2 id=&quot;what-makes-a-component-bulletproof%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/bulletproof-components/#what-makes-a-component-bulletproof%3F&quot;&gt;What makes a component bulletproof?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The term &lt;em&gt;bulletproof&lt;/em&gt; might be misleading, so let&#39;s consider this passage from Dan&#39;s book before we continue:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Out in the nonvirtual world, a bulletproof vest never guarantees complete, 100% protection, but rather being bulletproof is something that&#39;s constantly strived for. You&#39;re far better off wearing a bulletproof vest than if you weren&#39;t.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;What we&#39;re aiming for with bulletproof components isn&#39;t perfection. We&#39;re aiming for components that are as intuitive, flexible, and resilient as possible.&lt;/p&gt;
&lt;p&gt;Here are some of the key features that comprise a bulletproof component.&lt;/p&gt;
&lt;h3 id=&quot;ease-of-use&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/bulletproof-components/#ease-of-use&quot;&gt;Ease of Use&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Every component has an &lt;abbr title=&quot;Application Programming Interface&quot;&gt;API&lt;/abbr&gt; that serves as its primary interface for users. As a component author, many of your users are probably developers which means good &lt;abbr title=&quot;Developer Experience&quot;&gt;DX&lt;/abbr&gt; is critical. Offering consistent, predictable APIs is vital to good DX and therefore a fundamental feature of bulletproof components.&lt;/p&gt;
&lt;p&gt;If you have a library, for example, don&#39;t make the &lt;code&gt;size&lt;/code&gt; property accept &lt;code&gt;small|medium|large&lt;/code&gt; in one component and &lt;code&gt;sm|md|lg&lt;/code&gt; in another. As a user, if I&#39;ve used one or two of your components, I should be able to get the hang of things pretty quickly based on prior experience. Let me build on that knowledge as I go.&lt;/p&gt;
&lt;p&gt;Similarly, I should be able to glance at any component and have a pretty good idea what it does. I know you&#39;ve documented it, but when I see a component in the wild, I don&#39;t want to open the docs unless I absolutely have to.&lt;/p&gt;
&lt;p&gt;It&#39;s easy to overload a component with too many features. Oftentimes, that&#39;s a sign you should break it down further. Components that take on too much responsibility aren&#39;t only harder to use, they&#39;re harder to maintain too.&lt;/p&gt;
&lt;h3 id=&quot;versatility&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/bulletproof-components/#versatility&quot;&gt;Versatility&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Components are designed to be reused, so you never know where they&#39;ll end up in an application. Plan for this. Expect that users will drop your component into a 100×100 container, a 1200×1200 container, and everything in between. It&#39;s not that they&#39;re trying to break things, it&#39;s that edge cases happen &lt;em&gt;a lot&lt;/em&gt; and it&#39;s better to be prepared than to be caught off guard.&lt;/p&gt;
&lt;p&gt;As component developers, we can&#39;t predict every possible use case, but we can offer resilience by asking the right questions during development.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Does it break when I place it in common locations?&lt;/li&gt;
&lt;li&gt;Does it grow and shrink as the user will expect it to?&lt;/li&gt;
&lt;li&gt;How does it render on a mobile device? A tablet? An extra large screen?&lt;/li&gt;
&lt;li&gt;Is it accessible in all places it&#39;s likely to be used in?&lt;/li&gt;
&lt;li&gt;Does it work equally well on touch devices as it does with a mouse?&lt;/li&gt;
&lt;li&gt;Does it work properly as part of a composition?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sometimes it doesn&#39;t make sense to test for one thing or another. Use your best judgment and consider the intent. Nobody understands your users better than you, so adapt your questions accordingly.&lt;/p&gt;
&lt;h3 id=&quot;interoperability&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/bulletproof-components/#interoperability&quot;&gt;Interoperability&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As building blocks, components must work across a variety of applications. Unless your organization has a technical mandate, this usually means you need to support a variety of frameworks such as React, Vue, Angular, etc. Interoperability doesn&#39;t mean building the same component for every framework you need to support. It means &lt;em&gt;using the same exact components&lt;/em&gt; in every framework.&lt;/p&gt;
&lt;p&gt;This might sound like a web component plug but, realistically speaking, why wouldn&#39;t you want your components to work &lt;em&gt;everywhere&lt;/em&gt;? Interop is important because there&#39;s a lot of upfront costs, maintenance burdens, and technical debt that comes with building the same thing multiple times.&lt;/p&gt;
&lt;p&gt;Smaller orgs can get away with using a single framework for awhile, but it will eventually catch up to them. Which brings me to the next feature of bulletproof components…&lt;/p&gt;
&lt;h3 id=&quot;longevity&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/bulletproof-components/#longevity&quot;&gt;Longevity&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Congratulations! You&#39;ve built a component library using your favorite framework. Your users are happy and everything is great. They love the shiny new buttons you gave them!&lt;/p&gt;
&lt;p&gt;[a year or two later]&lt;/p&gt;
&lt;p&gt;Oh look, your favorite framework has evolved. Version 2 is out and that means breaking changes! Quite possibly lots of them. No worries though, version 1 is still, uh, kinda supported. You can probably keep using that for awhile. Wait, what&#39;s that? You say a number of teams in the company have already upgraded to version 2?&lt;/p&gt;
&lt;p&gt;Now you have &lt;em&gt;two&lt;/em&gt; component libraries to build and maintain! Or maybe you can endure the challenge of getting everyone in the org to upgrade their old apps. Neither situation is ideal for you, your users, or your organization. Web components can help mitigate this.&lt;/p&gt;
&lt;h3 id=&quot;documentation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/bulletproof-components/#documentation&quot;&gt;Documentation&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As a component author, I can tell you without question that most developers don&#39;t like to read documentation. Nevertheless, good documentation is a necessity for bulletproof components. But what exactly is &amp;quot;good documentation?&amp;quot;&lt;/p&gt;
&lt;p&gt;Good documentation isn&#39;t necessarily &lt;em&gt;comprehensive&lt;/em&gt; documentation. While it&#39;s certainly important to include all the relevant details of a component&#39;s usage, producing superfluous amounts of content is a disservice to your users. People aren&#39;t reading your documentation during their coffee break. They have work to do and they want to get it done efficiently. Make it easy for them to find what they need.&lt;/p&gt;
&lt;p&gt;Your component&#39;s documentation should be scannable. Tell me what it does. Tell me how to import it. Tell me what props are available. Fill the page with relevant examples and order them from most common to least common, leaving the edge cases for last. Call out important tips and gotchas in context so they&#39;re prominent, but not distracting.&lt;/p&gt;
&lt;p&gt;Don&#39;t let your content become stale. Nothing is more frustrating than docs that aren&#39;t aligned with a component&#39;s implementation. Avoid decoupling things that are likely to be forgotten over time.&lt;/p&gt;
&lt;p&gt;Code analyzers can help keep important things such as props, events, and more up to date by bringing the documentation closer to the to code. Remember how I said developers don&#39;t like to read? Most don&#39;t like to document things, either. Make it harder for them to &lt;em&gt;not&lt;/em&gt; document their changes.&lt;/p&gt;
&lt;h2 id=&quot;get-inspired&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/bulletproof-components/#get-inspired&quot;&gt;Get Inspired&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Building components is an art, and this post certainly isn&#39;t definitive nor comprehensive. My intent is to document, through experience and observations, the characteristics that make up &lt;em&gt;bulletproof components&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Consider this an ode to Dan&#39;s vision of &lt;em&gt;Bulletproof Web Design&lt;/em&gt; — an extension of a great idea adapted for component development.&lt;/p&gt;
&lt;p&gt;I&#39;m particularly proud of the work I&#39;ve done on &lt;a href=&quot;https://shoelace.style/&quot;&gt;Shoelace&lt;/a&gt;, a library of components that I purposefully maintain with longevity in mind. This project demonstrates all of the principles I&#39;ve described herein, and I encourage you to use it as inspiration in your own projects. I also encourage you to contribute to the paradigm of bulletproof components through discussion or demonstration &lt;a href=&quot;https://x.com/claviska&quot;&gt;via Twitter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I can&#39;t wait to see what you&#39;re working on!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Empowering Design System Users</title>
		<link href="https://www.abeautifulsite.net/posts/empowering-design-system-users/"/>
		<updated>2021-11-01T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/empowering-design-system-users/</id>
		<content type="html">&lt;p&gt;The question of whether or not component APIs should be locked down at the code level comes up quite a bit. For example, if a button spec only calls for primary, secondary, and tertiary variants, should we still expose &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/::part&quot;&gt;parts&lt;/a&gt; and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/--*&quot;&gt;custom properties&lt;/a&gt; so users can make further customization as needed?&lt;/p&gt;
&lt;p&gt;In my experience, the answer is &amp;quot;yes.&amp;quot;&lt;/p&gt;
&lt;p&gt;The arguments for locking things down seem to stem from designers who want pixel-perfect results. That&#39;s understandable — after all, engineers aren&#39;t usually known for their creative skills — but restraints have consequences.&lt;/p&gt;
&lt;p&gt;As design system engineers, we have to face the hard fact that, at some point, users are going to do things that are wrong. It&#39;s not our job to prevent them from doing those things. It&#39;s our job to give them tools that make it as easy as possible to do things that are &lt;em&gt;right&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;This may seem counterintuitive, but requirements change and designs evolve. The best way to experiment with new ideas is to customize what&#39;s already there. Neutering a component&#39;s API for the sake of design purity means it can no longer be used as a building block for new ideas.&lt;/p&gt;
&lt;p&gt;When your API is too rigid, users will do crazy things to work around it. I&#39;ve seen developers poke through the shadow root with JavaScript to add custom styles to encapsulated components. In another instance, a consumer built their own version of a component because we didn&#39;t expose any CSS parts. All the functionality was there — they just needed different styles.&lt;/p&gt;
&lt;p&gt;You might think you&#39;re doing your organization a favor by enforcing standards. I mean, the whole purpose of a design system is to encourage consistency, isn&#39;t it?!&lt;/p&gt;
&lt;p&gt;Absolutely, and you can do that with well-designed components and copy + paste examples that demonstrate their correct usage. Assuming developers &lt;em&gt;want&lt;/em&gt; to do the wrong thing is a fallacy. Most of them want to do the right thing and, given the tools, will seldom venture outside the walled garden that is your design system.&lt;/p&gt;
&lt;p&gt;But when users &lt;em&gt;do&lt;/em&gt; need to color outside the lines, taking away their crayons won&#39;t stop them. They&#39;ll just grab the closest Sharpie and do it anyway.&lt;/p&gt;
&lt;p&gt;Empower your users and you&#39;ll save everyone a lot of time and frustration.&lt;/p&gt;
&lt;hr /&gt;
&lt;small&gt;
&lt;p&gt;Take advantage of design reviews to understand how consumers are using your components. What customizations have they made? What pain points did they have implementing them? Use this feedback to improve your offering, but &lt;a href=&quot;https://www.abeautifulsite.net/posts/know-when-to-draw-the-line/&quot;&gt;know when to draw the line&lt;/a&gt;.&lt;/p&gt;
&lt;/small&gt;
</content>
	</entry>
	
	<entry>
		<title>Exploring the EyeDropper API</title>
		<link href="https://www.abeautifulsite.net/posts/exploring-the-eyedropper-api/"/>
		<updated>2021-10-26T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/exploring-the-eyedropper-api/</id>
		<content type="html">&lt;p&gt;The &lt;a href=&quot;https://github.com/WICG/eyedropper-api&quot;&gt;EyeDropper API&lt;/a&gt; has landed in &lt;a href=&quot;https://www.chromestatus.com/feature/6304275594477568&quot;&gt;Chrome and Edge 95&lt;/a&gt;! This is a simple promise-based API that lets you select a color from anywhere on the screen. Let&#39;s dive in and see how it works.&lt;/p&gt;
&lt;p&gt;To start, we&#39;ll add a button that activates the eye dropper.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Select a color&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When the button is clicked, we&#39;ll launch the eye dropper. As soon as the user selects a color, we&#39;ll update the page&#39;s background to match.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; button &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;button&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;EyeDropper&#39;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; eyeDropper &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;EyeDropper&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  button&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;click&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    eyeDropper
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;colorSelectionResult&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;backgroundColor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; colorSelectionResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sRGBHex&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// The user canceled selection&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// The EyeDropper API isn&#39;t supported&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://codepen.io/claviska/pen/OJjmMgz?editors=1010&quot;&gt;Try it on CodePen&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;breaking-it-down&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/exploring-the-eyedropper-api/#breaking-it-down&quot;&gt;Breaking it down&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here&#39;s what&#39;s happening in the code above:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Feature-detect the API&lt;/li&gt;
&lt;li&gt;Instantiate an EyeDropper object&lt;/li&gt;
&lt;li&gt;Listen for button clicks&lt;/li&gt;
&lt;li&gt;Call the eye dropper&#39;s &lt;code&gt;open()&lt;/code&gt; method, which returns a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;Promise&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Wait for the promise to resolve (the user selected a color) or reject (the user canceled selection)&lt;/li&gt;
&lt;li&gt;On resolve, grab the hex value and set the background&lt;/li&gt;
&lt;li&gt;On reject, do nothing (the empty &lt;code&gt;catch&lt;/code&gt; will prevent an error hitting the console)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Note how I&#39;m feature-detecting the EyeDropper API. This is important because, at the time of this writing, Firefox and Safari don&#39;t support it. That doesn&#39;t mean you can&#39;t use the API to progressively enhance your users&#39; experience, though!&lt;/p&gt;
&lt;p&gt;For example, I&#39;m using it in &lt;a href=&quot;https://x.com/claviska/status/1452990807640875011?s=20&quot;&gt;Shoelace&#39;s color picker&lt;/a&gt; to show an eye dropper if the API is available. Otherwise, I don&#39;t show the eye dropper but everything else still works.&lt;/p&gt;
&lt;h2 id=&quot;another-example&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/exploring-the-eyedropper-api/#another-example&quot;&gt;Another Example&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I whipped up another example that&#39;s a bit more practical. Play around with it and let me know what you think!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://codepen.io/claviska/pen/ExvmjqQ&quot;&gt;Try it on CodePen&lt;/a&gt;&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>The Future of Frameworks</title>
		<link href="https://www.abeautifulsite.net/posts/the-future-of-frameworks/"/>
		<updated>2021-10-25T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/the-future-of-frameworks/</id>
		<content type="html">&lt;p&gt;Love them or hate them, web components (&amp;quot;custom elements&amp;quot;) are making a huge dent in the world of front-end development. As of today, &lt;a href=&quot;https://x.com/claviska/status/1452621707576029194&quot;&gt;close to 18% of page views in Chrome&lt;/a&gt; are registering web components. That&#39;s an insane amount of usage!&lt;/p&gt;
&lt;p&gt;The benefits of a framework-agnostic component model are becoming obvious to web developers, particularly those who have built the same components over and over again to accommodate various framework flavors. That kind of rework is a time sink that inevitably leads to visual and functional inconsistencies. Maintaining multiple versions of the same component isn&#39;t a winning strategy for developers, designers, or end users.&lt;/p&gt;
&lt;p&gt;Web components solve this problem not by replacing frameworks, but by &lt;em&gt;complementing&lt;/em&gt; them with a &lt;a href=&quot;https://github.com/WICG/webcomponents#readme&quot;&gt;standardized component model&lt;/a&gt;. Create your lower-level building blocks as custom elements, then plug them into a framework that handles higher-level operations. When it&#39;s time to upgrade or switch frameworks, you can do it more easily because you don&#39;t have to rip out the foundation and rebuild everything from scratch. Interoperability is why web component-based design systems are so appealing to large organizations.&lt;/p&gt;
&lt;p&gt;My prediction is that front-end frameworks will move away from proprietary component models and embrace custom elements as first-class citizens. Both &lt;a href=&quot;https://v3.vuejs.org/guide/web-components.html#building-custom-elements-with-vue&quot;&gt;Vue&lt;/a&gt; and &lt;a href=&quot;https://svelte.dev/docs#Custom_element_API&quot;&gt;Svelte&lt;/a&gt; provide mechanisms for authoring them — although they still use and support their own component models as well.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;quot;But I don&#39;t plan on switching frameworks!&amp;quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Unlike diamonds, frameworks aren&#39;t forever.* They come and go and, as their popularity fades, so does support, contributions, and community interest. Contrast this to web standards that browsers commit to supporting without breaking changes.&lt;/p&gt;
&lt;p&gt;We&#39;ve been building and rebuilding buttons for years because the component model has been baked into our frameworks. We don&#39;t need to do that anymore. If longevity is a goal, custom elements are where it&#39;s at.&lt;/p&gt;
&lt;hr /&gt;
&lt;small&gt;
&lt;p&gt;*Whether you consider React a framework or a library is irrelevant. It has its own &lt;a href=&quot;https://reactjs.org/docs/react-component.html&quot;&gt;component model&lt;/a&gt;, &lt;a href=&quot;https://reactjs.org/docs/faq-internals.html&quot;&gt;VDOM&lt;/a&gt;, and &lt;a href=&quot;https://reactjs.org/docs/events.html&quot;&gt;synthetic event system&lt;/a&gt;. If it walks like a framework and talks like a framework…&lt;/p&gt;
&lt;/small&gt;
</content>
	</entry>
	
	<entry>
		<title>Superpowers</title>
		<link href="https://www.abeautifulsite.net/posts/superpowers/"/>
		<updated>2021-10-12T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/superpowers/</id>
		<content type="html">&lt;p&gt;I stumbled upon &lt;a href=&quot;https://www.bryanbraun.com/2018/02/18/the-cure-for-boredom-is-superpowers/&quot;&gt;a short post&lt;/a&gt; that intrigued me. In it, the author claims that the cure for boredom is superpowers. Not superpowers in the Superman sense, but ones that we can teach ourselves.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Learn Photoshop, and you’ll have a superpower. You’ll be able to see what your bedroom would look like with blue walls, improve the lighting in your craigslist posting, make custom christmas cards, do your own wedding invitations, and more.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is true. I remember what it was like when I started learning Photoshop. I spent hours following &lt;a href=&quot;https://robouk.com/tutorials/photoshop/&quot;&gt;Robouk&#39;s Photoshop tutorials&lt;/a&gt; (which are, impressively, still online in 2021) and even more time cropping my head onto various movie posters. I still have some of them lying around.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/we-were-soldiers.jpg&quot; alt=&quot;My face photoshopped onto a We Were Soldiers movie poster&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Those skills — er, superpowers — complemented the programming skills I learned as a teenager and ultimately led to me becoming a software engineer.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Many of us haven’t been bored in years. If that sounds unbelievable, maybe you should learn to fly too.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Thinking about it, I genuinely can&#39;t recall the last time I was bored. If anything, I wish there were more time in the day to do all the things I want to get done.&lt;/p&gt;
&lt;p&gt;It may not feel like flying, but it does feel a bit like having superpowers.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Know When To Draw The Line</title>
		<link href="https://www.abeautifulsite.net/posts/know-when-to-draw-the-line/"/>
		<updated>2021-10-11T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/know-when-to-draw-the-line/</id>
		<content type="html">&lt;p&gt;One-off variations aren&#39;t uncommon, but they don&#39;t belong in your design system. You&#39;re design system isn&#39;t solving for every possible use case — it&#39;s encouraging visual consistency and efficient development. Use custom styles for one-offs.&lt;/p&gt;
&lt;p&gt;This came up recently on my team.&lt;/p&gt;
&lt;p&gt;We have a button component that supports prefix icons. By default, the icon color matches the text. In one design, the same button was used but the icon color was the primary color instead. The question came up:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;Should we make a new button variant?&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The answer, of course, was no. Because the button should only look like that in a specific toolbar, the solution was something like:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;my-toolbar my-button::part(icon)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--primary&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Know when to draw the line.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Don&#39;t Do Magic</title>
		<link href="https://www.abeautifulsite.net/posts/dont-do-magic/"/>
		<updated>2021-10-11T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/dont-do-magic/</id>
		<content type="html">&lt;p&gt;We recently had a design for an &amp;quot;alert&amp;quot; component with an &lt;code&gt;actions&lt;/code&gt; slot. In the spec, only secondary buttons were allowed in it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Dev: &amp;quot;Design only wants secondary buttons in the actions slot, so I&#39;m forcing it.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The developer was listening for the &lt;code&gt;slotchange&lt;/code&gt; event and applying the &lt;code&gt;secondary&lt;/code&gt; variant to all buttons in the slot automatically. The idea was to prevent consumers from using the wrong buttons by constraining the design in code. This magic will cause problems.&lt;/p&gt;
&lt;p&gt;Here&#39;s the thing: designers change their minds. Sometimes a lot. They might &lt;em&gt;tell&lt;/em&gt; you that a design will never, ever change. They might swear to everything holy that it will never change. But it can and often will.&lt;/p&gt;
&lt;p&gt;In this case, forcing a variant on slotted buttons changed them from:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;my-button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;my-button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;appearance&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;secondary&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Aside from being unexpected, it leaves the user with no obvious way to add anything other than a secondary button to the slot.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;But that&#39;s what design wants!&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;...until they realize they need a primary action button in that slot. Now you have to write code to account for this new requirement, PR it, get it reviewed, approved, and push a new version so they can use it. Problem solved, right?&lt;/p&gt;
&lt;p&gt;Not so fast…&lt;/p&gt;
&lt;h2 id=&quot;scopes-change&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/dont-do-magic/#scopes-change&quot;&gt;Scopes Change&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Turns out, another team is using the same component to prototype a new feature and they want to use all possible button variations. This isn&#39;t the use case the design team initially specced the component for, but it doesn&#39;t make sense to create one from scratch because this one is close enough. Due to time and cost constraints, management decides the existing component should be modified to support both use cases.&lt;/p&gt;
&lt;p&gt;Boom. The design that won&#39;t change has changed.&lt;/p&gt;
&lt;p&gt;But remember the magic we coded that forced all slotted buttons to be secondary buttons? Because of that, we have to introduce a breaking change in our alert component OR give users an alternate API that&#39;s inconsistent with how buttons already work. Neither option is great.&lt;/p&gt;
&lt;p&gt;In my opinion, locking design choices down with code, or &amp;quot;magic,&amp;quot; is an antipattern. It creates more work for devs, makes things less intuitive for users, and introduces tech debt that will haunt you later on.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;Well then how do we force users to use the right buttons?&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We don&#39;t! That&#39;s not our job. Neither design nor engineering can account for every possible use case for the components we build.&lt;/p&gt;
&lt;p&gt;Our job is to give users tools to build things with. If I give you a hammer and you smash a hole in the wall instead of tapping in a nail, that&#39;s a misuse of the tool.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/hammer-oops.gif&quot; alt=&quot;Hammering a hole into the wall. Oops.&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;when-bulletproofing-is-overengineering&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/dont-do-magic/#when-bulletproofing-is-overengineering&quot;&gt;When Bulletproofing is Overengineering&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As engineers, it can be tempting to make components &amp;quot;bulletproof&amp;quot; using ✨magic✨ code. This is usually an overstep. There are two things you shouldn&#39;t underestimate:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The importance of design reviews&lt;/li&gt;
&lt;li&gt;Use cases that evolve over time&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you&#39;re not taking the time to do design reviews, do them! But don&#39;t wait until the very end. You&#39;ll have better success if design and engineering work together &lt;em&gt;throughout&lt;/em&gt; the process.&lt;/p&gt;
&lt;p&gt;As for magic — I consider it a code smell. If you find yourself forcing things like this via code, that&#39;s a red flag. A better approach is good documentation! Show examples of approved use cases. Give users code to copy and paste. Make it easy for them to get it right.&lt;/p&gt;
&lt;p&gt;Users will definitely do things they&#39;re not supposed to. Get comfortable with that and catch it in design reviews. Use these instances to understand &lt;em&gt;why&lt;/em&gt; they&#39;re doing it that way and work with design to iterate if necessary. These are great opportunities to learn from each other.&lt;/p&gt;
&lt;p&gt;Don&#39;t assume users are dumb or just don&#39;t get it. Give them the tools they need and make it easy for them to succeed. Most importantly, listen to feedback and know when it&#39;s time to steer them away from incorrect usage vs. adapting the tooling for new requirements.&lt;/p&gt;
&lt;hr /&gt;
&lt;small&gt;
&lt;p&gt;This post was originally &lt;a href=&quot;https://x.com/claviska/status/1447562886314971141?s=20&quot;&gt;a series of tweets&lt;/a&gt;.&lt;/p&gt;
&lt;/small&gt;
</content>
	</entry>
	
	<entry>
		<title>On Buttons and Links</title>
		<link href="https://www.abeautifulsite.net/posts/on-buttons-and-links/"/>
		<updated>2021-10-06T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/on-buttons-and-links/</id>
		<content type="html">&lt;p&gt;I posted a tweet yesterday that was met with some controversy, so I thought it would be a good idea to unravel it.&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Unpopular opinion: in a design system, a &amp;quot;link&amp;quot; and a &amp;quot;button&amp;quot; should be one component.&lt;/p&gt;&amp;mdash; Cory LaViska (@claviska) &lt;a href=&quot;https://x.com/claviska/status/1445479402532261892?ref_src=twsrc%5Etfw&quot;&gt;October 5, 2021&lt;/a&gt;&lt;/blockquote&gt; &lt;script async=&quot;&quot; src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;p&gt;At face value, I understand why people are upset with this. It&#39;s hard to provide context in 280 characters, though, so &lt;a href=&quot;https://x.com/claviska/status/1445479402532261892&quot;&gt;I made it a thread&lt;/a&gt;. That was a mistake, because people don&#39;t always read the thread so the intent gets lost and assumptions get made. Twitter is a wonderful place.&lt;/p&gt;
&lt;h2 id=&quot;semantically-different&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/on-buttons-and-links/#semantically-different&quot;&gt;Semantically Different&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let&#39;s start by stating the obvious. A button and a link are &lt;a href=&quot;https://www.webaxe.org/proper-use-buttons-links/&quot;&gt;semantically different HTML elements&lt;/a&gt;, so no need to bust out the keyboard to tell me that. The idea of merging the two into a single component comes from real world experience working on multiple design system teams for large companies.&lt;/p&gt;
&lt;p&gt;The fact is that designers always, always ask for links that look like buttons and buttons that look like links. I know, &lt;a href=&quot;https://twitter.com/oliverturner/status/1445724464860127244?s=20&quot;&gt;designers shouldn&#39;t do this&lt;/a&gt;. But this isn&#39;t a fantasy, it&#39;s our reality, and &lt;a href=&quot;https://x.com/claviska/status/1445722314889437184&quot;&gt;when it costs your organization measurable value&lt;/a&gt; in terms of conversions, sales, etc., you&#39;re not going to win that argument.&lt;/p&gt;
&lt;p&gt;Emotions aside, this often leads to developers producing two separate &lt;a href=&quot;https://explore.fast.design/components/fast-button&quot;&gt;button&lt;/a&gt; and &lt;a href=&quot;https://explore.fast.design/components/fast-anchor&quot;&gt;link&lt;/a&gt; components with the same styles and logic, and consumers end up misusing them just like &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To alleviate this, &lt;a href=&quot;https://x.com/claviska/status/1445480631832436747&quot;&gt;I propose that a custom element&lt;/a&gt; such as &lt;code&gt;&amp;lt;my-button&amp;gt;&lt;/code&gt; should render the same &amp;quot;button&amp;quot; visually, but based on the presense of an optional &lt;code&gt;href&lt;/code&gt; attribute, it will use a &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; or an &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; under the hood.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;my-button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Save&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;my-button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- 👉 &amp;lt;button class=&quot;button button--primary&quot;&gt;Save&amp;lt;/button&gt; --&gt;&lt;/span&gt;

&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;my-button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/new&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;New&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;my-button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- 👉 &amp;lt;a class=&quot;button button--primary&quot; href=&quot;/new&quot;&gt;New&amp;lt;/a&gt; --&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This makes it more foolproof — if it goes somewhere, it becomes a link. If not, it&#39;s remains a button. So far, we&#39;re more or less aligned with the Twittersphere…&lt;a href=&quot;https://twitter.com/EmmaJ_PR/status/1445664177821925387?s=20&quot;&gt;except for one detail&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;They should look different because they should do different things.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;visually-different%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/on-buttons-and-links/#visually-different%3F&quot;&gt;Visually Different?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As much as I want to agree with this statement, it falls apart in practice. &lt;em&gt;Links will inevitably need to look like buttons from time to time.&lt;/em&gt; No, buttons and links are not &lt;em&gt;semantically&lt;/em&gt; the same, but there are times when they need to be &lt;em&gt;visually&lt;/em&gt; the same.&lt;/p&gt;
&lt;p&gt;In web apps, the function of buttons and links is often blended. Some actions, such as &amp;quot;new,&amp;quot; might simply open a new page. Others aren&#39;t as obvious. &amp;quot;Save&amp;quot; might fire off an &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest&quot;&gt;XHR&lt;/a&gt; and redirect you to another page if the response is successful — or go nowhere and show an error if the response fails.&lt;/p&gt;
&lt;p&gt;Suddenly, the line between &amp;quot;button&amp;quot; and &amp;quot;link&amp;quot; is more blurry. Should it still be a link if it takes me somewhere only &lt;em&gt;after&lt;/em&gt; an XHR is successful? What if the request errors out and doesn&#39;t redirect? What if you click a link and the app prevents navigation because you have unsaved changes? There are so many scenarios and &amp;quot;what ifs&amp;quot; that, in practice, it&#39;s hard to settle on a 100% agreeable definition.&lt;/p&gt;
&lt;p&gt;And then comes the design team with a Figma for the app&#39;s toolbar.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/toolbar-with-buttons.png&quot; alt=&quot;Button group with four actions: new, edit, settings, download&quot; /&gt;&lt;/p&gt;
&lt;p&gt;We&#39;ll assume that &amp;quot;New&amp;quot; takes you to &lt;code&gt;/new&lt;/code&gt; and &amp;quot;Edit&amp;quot; takes you to &lt;code&gt;/edit/:id&lt;/code&gt;. Those should definitely be links! But wait — &amp;quot;Settings&amp;quot; doesn&#39;t go anywhere. It just opens up a dialog, so it needs to be a button. And instead of creating an endpoint on the server that downloads the file, we&#39;ll use the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#attr-download&quot;&gt;&lt;code&gt;download&lt;/code&gt;&lt;/a&gt; attribute so that also needs to be a link.&lt;/p&gt;
&lt;p&gt;Let&#39;s adjust the design to account for the idea that buttons and links &lt;em&gt;must&lt;/em&gt; be visually different.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/toolbar-with-buttons-and-links.png&quot; alt=&quot;A button group with a new link, edit link, settings button, and a download link&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Do you think the design team is going to be thrilled with these changes to the toolbar? Do you think your customers will prefer this toolbar over the previous one?&lt;/p&gt;
&lt;h2 id=&quot;what-users-expect&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/on-buttons-and-links/#what-users-expect&quot;&gt;What Users Expect&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If the user is presented with a set of actions, &lt;em&gt;they don&#39;t care if you use buttons or links under the hood&lt;/em&gt;. They care that it&#39;s consistent and that each control does what it&#39;s supposed to do. Remember that in all cases, each control&#39;s action is clearly inferred from its label.&lt;/p&gt;
&lt;p&gt;Whether clicking &amp;quot;Delete&amp;quot; takes the user to a new page to confirm or opens a dialog to confirm is irrelevant. To the user, they&#39;re all just &amp;quot;buttons&amp;quot; that do something.*&lt;/p&gt;
&lt;p&gt;It is true that links and buttons have different behaviors and the decision to make them look visually similar should be carefully considered. For example, &lt;kbd&gt;CMD&lt;/kbd&gt; or &lt;kbd&gt;CTRL&lt;/kbd&gt; + click typically opens a link in a new window. When buttons and links are identical, it can put users at a disadvantage.&lt;/p&gt;
&lt;p&gt;I would recommend &lt;em&gt;not&lt;/em&gt; making buttons and links look the same if you can reasonably expect the user will desire such behaviors. Some environments are more predictable than others. But accessibility isn&#39;t binary, so thought and consideration is still required from both design and development regardless of your approach.&lt;/p&gt;
&lt;h2 id=&quot;enforcement-via-api&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/on-buttons-and-links/#enforcement-via-api&quot;&gt;Enforcement via API&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The suggestion I&#39;m making enforces the semantic definition of &amp;quot;button&amp;quot; and &amp;quot;link&amp;quot; by leaning on API design to ensure &lt;abbr title=&quot;Don&#39;t repeat yourself&quot;&gt;DRY&lt;/abbr&gt; principles and remove the burden of thought from consumers. This solves the problem of when to use a link or button under the hood.&lt;/p&gt;
&lt;p&gt;It does not answer the question of &amp;quot;&lt;em&gt;should buttons and links be visually similar&lt;/em&gt;?&amp;quot; That&#39;s a topic I&#39;d love to have a conversation about because there are plenty of use cases that suggest at least sometimes they should.&lt;/p&gt;
&lt;p&gt;Just know that, if you&#39;re working on a design system, it&#39;s extremely likely you will come across this requirement!&lt;/p&gt;
&lt;hr /&gt;
&lt;small&gt;
&lt;p&gt;*This doesn&#39;t mean you should throw the baby out with the bathwater. It just means there might be situations where you need to use a link as a button, and the user doesn&#39;t care as long as it works. The download example comes to mind.&lt;/p&gt;
&lt;/small&gt;
</content>
	</entry>
	
	<entry>
		<title>On Using Web Component Libraries</title>
		<link href="https://www.abeautifulsite.net/posts/on-using-web-component-libraries/"/>
		<updated>2021-09-20T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/on-using-web-component-libraries/</id>
		<content type="html">&lt;p&gt;We tend to think of components as things that belong to a framework. After all, React has components, Vue has components, Angular has components…it&#39;s just how we&#39;ve always used them.&lt;/p&gt;
&lt;p&gt;Because of that, people tend to refer to &lt;a href=&quot;https://lit.dev/&quot;&gt;Lit&lt;/a&gt; and &lt;a href=&quot;https://www.fast.design/docs/fast-element/getting-started/&quot;&gt;FAST Element&lt;/a&gt; as frameworks, but they’re not. They’re &lt;em&gt;libraries&lt;/em&gt;, and that’s an important distinction.&lt;/p&gt;
&lt;p&gt;If you want a React component to work, you have to use it with React. If you want a Vue component to work, you have to use it with Vue. If you want an Angular component to work…well, you get the point.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;With web components, the platform is the framework.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Naturally, a follow up question is &amp;quot;why do you need a library then?&amp;quot; The truth is that we don’t. We can create web components without a library. &lt;a href=&quot;https://codepen.io/claviska/pen/abwGLPm?editors=0010&quot;&gt;Here&#39;s a counter component written in pure JavaScript&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyCounter&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HTMLElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;observedAttributes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;count&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;attachShadow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;open&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;shadowRoot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;innerHTML &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
      &amp;lt;button type=&quot;button&quot;&gt;
        Count:
        &amp;lt;span class=&quot;count&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;count&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/span&gt;
      &amp;lt;/button&gt;
    &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;handleClick &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;handleClick&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;connectedCallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;shadowRoot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;button&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;click&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;handleClick&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;disconnectedCallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;shadowRoot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;button&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;removeEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;click&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;handleClick&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;count&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;newCount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;count &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; newCount&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;attributeChangedCallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; oldValue&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; newValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;count&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;count &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;newValue&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;handleClick&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;count &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;count &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;shadowRoot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;.count&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;count&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

customElements&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;my-counter&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; MyCounter&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We &lt;em&gt;choose&lt;/em&gt; to use libraries to improve the the component authoring experience and abstract messy boilerplate into efficient, reusable modules. &lt;a href=&quot;https://codepen.io/claviska/pen/LYLmzKL?editors=0010&quot;&gt;Here&#39;s a functionally equivalent counter built with Lit&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; LitElement&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; html &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;lit&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; customElement&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; property &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;lit/decorators.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;customElement&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;my-counter&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyCounter&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LitElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;property&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Number &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; count &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;handleClick&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;count&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
      &amp;lt;button type=&quot;button&quot; @click=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;handleClick&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&gt;
        Count: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;count&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
      &amp;lt;/button&gt;
    &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sure, we can bake features such as declarative rendering and reactivity into each and every component, but that’s not &lt;abbr title=&quot;Don&#39;t Repeat Yourself&quot;&gt;DRY&lt;/abbr&gt;. It would convolute the code and make our components larger and more difficult to maintain. That’s not what I want and it&#39;s probably not what my users want.&lt;/p&gt;
&lt;p&gt;Alternatively, we could build those features ourselves and split them off into reusable modules — but that&#39;s just reinventing the wheel, isn&#39;t it?&lt;/p&gt;
&lt;p&gt;When you think of it that way, using a library to build web components makes a lot of sense.&lt;/p&gt;
&lt;hr /&gt;
&lt;small&gt;
&lt;p&gt;Aside: &lt;a href=&quot;https://twitter.com/evanplaice/status/1420922358534049804?s=20&quot;&gt;It’s been said&lt;/a&gt; that developer experience is the only benefit to using a library. While it’s true that benefits to the end user are marginalized with one-off components, it&#39;s worth noting that APIs such as those offered by Lit and FAST Element lead to less bugs due to reduced complexity and less code in the component itself. Consider the counter examples above. Which one is easier to maintain?&lt;/p&gt;
&lt;/small&gt;
</content>
	</entry>
	
	<entry>
		<title>Finding the Closest Element Through Shadow Roots</title>
		<link href="https://www.abeautifulsite.net/posts/finding-the-closest-element-through-shadow-roots/"/>
		<updated>2021-09-13T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/finding-the-closest-element-through-shadow-roots/</id>
		<content type="html">&lt;p&gt;A great trick to find the closest element in the DOM that matches an arbitrary selector is &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element/closest&quot;&gt;&lt;code&gt;Element.closest()&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Starts at el and walks the DOM until it finds a parent element&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// that matches the selector. In this case, it will return the&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &amp;lt;body&gt; element.&lt;/span&gt;
el&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;closest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;body&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But what happens if you do this from inside a custom element&#39;s &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot&quot;&gt;shadow root&lt;/a&gt;?&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;someElementInShadowRoot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;closest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;body&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By design, &lt;code&gt;Element.closest()&lt;/code&gt; will not break out of the shadow root, so &lt;code&gt;null&lt;/code&gt; is returned.&lt;/p&gt;
&lt;p&gt;In my case, I needed to determine the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/lang&quot;&gt;&lt;code&gt;lang&lt;/code&gt;&lt;/a&gt; of the closest element, even if the element was outside of a shadow root. Time for some recursive magic! ✨&lt;/p&gt;
&lt;p&gt;Here&#39;s a TypeScript function that will do just that, even if the root is buried in multiple layers of shadow roots.&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;closest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;selector&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; root&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Element &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getNext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;el&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Element &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; HTMLElement&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; next &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; el &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; el&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;closest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;selector&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Element &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;el &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Window&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; el &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Document&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;el&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; next &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; next &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getNext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;el&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getRootNode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; ShadowRoot&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;host&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getNext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;root&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can use it like this:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Matches the closest element with a lang attribute, even if&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// it&#39;s outside of the shadow root&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; closestEl &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;closest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;[lang]&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; el&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content>
	</entry>
	
	<entry>
		<title>Testing Support for :focus-visible</title>
		<link href="https://www.abeautifulsite.net/posts/testing-support-for-focus-visible/"/>
		<updated>2021-08-24T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/testing-support-for-focus-visible/</id>
		<content type="html">&lt;p&gt;The new &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible&quot;&gt;&lt;code&gt;:focus-visible&lt;/code&gt;&lt;/a&gt; CSS selector lets us remove unsightly focus rings that often result in developers adding this to their stylesheets:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* Please don&#39;t do this */&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;button:focus&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;outline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While unsightly to mouse users, a clear focus indicator is essential for proper accessibility. How else will keyboard users, for example, know which element has focus?&lt;/p&gt;
&lt;p&gt;Fortunately, &lt;code&gt;:focus-visible&lt;/code&gt; gives us a way to make everyone happy by only applying focus styles when the user is interacting with a keyboard.&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;button:focus-visible&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;outline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; dashed 2px orange&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&#39;s &lt;a href=&quot;https://caniuse.com/mdn-css_selectors_focus-visible&quot;&gt;currently available in all browsers &lt;em&gt;except&lt;/em&gt; Safari&lt;/a&gt;. Well, it &lt;em&gt;is&lt;/em&gt; available in Safari Technology Preview, but it&#39;s buried under the experimental features menu and it&#39;s not clear when it will land in mainstream Safari.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/WICG/focus-visible&quot;&gt;There&#39;s a polyfill&lt;/a&gt; you can use in the meantime but, since you can&#39;t polyfill pseudo selectors, it applies a &lt;code&gt;focus-visible&lt;/code&gt; class instead. It&#39;s still useful if you really want this behavior, though!&lt;/p&gt;
&lt;h2 id=&quot;detecting-support&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/testing-support-for-focus-visible/#detecting-support&quot;&gt;Detecting Support&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;re trying to figure out how to feature detect &lt;code&gt;:focus-visible&lt;/code&gt;, you might be surprised to learn that there isn&#39;t an obvious way to do it — but there is a way!&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hasFocusVisible&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; style &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;style&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; isSupported&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;head&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sheet&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;insertRule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;:focus-visible { color: inherit }&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    isSupported &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    isSupported &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;finally&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; isSupported&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The secret sauce is in &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/insertRule&quot;&gt;&lt;code&gt;CSSStyleSheet.insertRule()&lt;/code&gt;&lt;/a&gt;, which will throw an error if you pass in a style it doesn&#39;t understand.&lt;/p&gt;
&lt;p&gt;You can use it like this.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hasFocusVisible&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Supported!&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Not supported&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This can be pretty helpful if you&#39;re building something and you want to provide different behaviors depending on the browser&#39;s support for &lt;code&gt;:focus-visible&lt;/code&gt;.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Querying through shadow roots</title>
		<link href="https://www.abeautifulsite.net/posts/querying-through-shadow-roots/"/>
		<updated>2021-08-04T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/querying-through-shadow-roots/</id>
		<content type="html">&lt;p&gt;Let&#39;s say I have a web component with an open shadow root, like this one from &lt;a href=&quot;https://shoelace.style/&quot;&gt;Shoelace&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;sl-button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Click me&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;sl-button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Inside the shadow root is a &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; that I want to target with JavaScript.* Alas, &lt;code&gt;Element.querySelector()&lt;/code&gt; doesn&#39;t offer a shortcut for traversing shadow roots so we have to do this.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; button &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;sl-button&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;shadowRoot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;button&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&#39;s pretty verbose! It&#39;s nice that we can chain the selectors, but it would be even nicer if we could poke through shadow roots &lt;em&gt;right in&lt;/em&gt; the selector.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// This doesn&#39;t work, but we can dream&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; button &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;sl-button &gt;&gt;&gt; button&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Well, here&#39;s a TypeScript function that gets us pretty close to that.&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;shadowQuery&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;selector&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; rootNode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Document &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; Element &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Element &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; selectors &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;selector&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;&gt;&gt;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; currentNode &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; rootNode&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  selectors&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;selector&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; index&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;index &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      currentNode &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; rootNode&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;selectors&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; Element&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;currentNode &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Element&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      currentNode &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; currentNode&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;shadowRoot&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;selectors&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; Element&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; currentNode &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;currentNode &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; rootNode&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; currentNode &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; Element &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This let&#39;s you use &lt;code&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt; in your selector instead of splitting it into multiple queries, resulting in a much simpler syntax.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; button &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;shadowQuery&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;sl-button &gt;&gt;&gt; button&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Querying starts on &lt;code&gt;document&lt;/code&gt; by default, but you can pass a node as the second argument to change that.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; container &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;.your-root-node&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; button &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;shadowQuery&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;sl-button &gt;&gt;&gt; button&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; container&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, you can even traverse multiple shadow roots in one query.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;shadowQuery&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;my-element &gt;&gt;&gt; my-second-element &gt;&gt;&gt; my-third-element&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;*It&#39;s worth noting that you probably &lt;em&gt;shouldn&#39;t&lt;/em&gt; be targeting shadow roots — they&#39;re encapsulated for a reason! Nevertheless, this can be very useful in exceptional situations.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Prefers Reduced Motion</title>
		<link href="https://www.abeautifulsite.net/posts/prefers-reduced-motion/"/>
		<updated>2021-05-19T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/prefers-reduced-motion/</id>
		<content type="html">&lt;p&gt;By now, most devs are familiar with the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion&quot;&gt;&lt;code&gt;prefers-reduced-motion&lt;/code&gt;&lt;/a&gt; media query that tells whether or not a user prefers, well, reduced motion. You can use this to tone down (or turn off) transitions and animations in your stylesheet to accommodate users with vestibular motion disorders.&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.animation&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* normal animation */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;prefers-reduced-motion&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token selector&quot;&gt;.animation&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;/* subtle or no animation */&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&#39;s pretty useful, but if you&#39;re using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API&quot;&gt;Web Animations API&lt;/a&gt;, you may want to check for this with JavaScript instead. Thanks to &lt;code&gt;window.matchMedia&lt;/code&gt;, it&#39;s pretty easy to do. I like to wrap it up in a small function that returns a boolean: &lt;code&gt;true&lt;/code&gt; if the users prefers reduced motion or &lt;code&gt;false&lt;/code&gt; if they have no preference.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;prefersReducedMotion&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; query &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;matchMedia&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;(prefers-reduced-motion: reduce)&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; query&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;matches&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Usage looks something like this:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;prefersReducedMotion&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// subtle or no animation&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// normal animation&lt;/span&gt;
  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;.my-element&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;animate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content>
	</entry>
	
	<entry>
		<title>Finding the active element in a shadow root</title>
		<link href="https://www.abeautifulsite.net/posts/finding-the-active-element-in-a-shadow-root/"/>
		<updated>2021-03-22T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/finding-the-active-element-in-a-shadow-root/</id>
		<content type="html">&lt;p&gt;You can get the focused element with &lt;code&gt;document.activeElement&lt;/code&gt; but, if it&#39;s inside a shadow root, this will be the &lt;em&gt;host element&lt;/em&gt;. This happens because of retargeting, but sometimes you might need access to the internal element that actually has focus.&lt;/p&gt;
&lt;p&gt;Here&#39;s a recursive function that will return the internal element that has focus, even if it&#39;s inside a shadow root.&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getActiveElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;root&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Document &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; ShadowRoot &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Element &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; activeEl &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; root&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;activeElement&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;activeEl&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;activeEl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;shadowRoot&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getActiveElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;activeEl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;shadowRoot&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; activeEl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Usage:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; activeEl &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getActiveElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content>
	</entry>
	
	<entry>
		<title>Moving from Stencil to LitElement</title>
		<link href="https://www.abeautifulsite.net/posts/moving-from-stencil-to-lit-element/"/>
		<updated>2021-03-02T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/moving-from-stencil-to-lit-element/</id>
		<content type="html">&lt;p&gt;Over the weekend, I finished migrating &lt;a href=&quot;https://shoelace.style/&quot;&gt;Shoelace&lt;/a&gt; from &lt;a href=&quot;https://stenciljs.com/&quot;&gt;Stencil&lt;/a&gt; to &lt;a href=&quot;https://www.abeautifulsite.net/posts/moving-from-stencil-to-lit-element/&quot;&gt;LitElement&lt;/a&gt;. Even though consumers of the library won&#39;t see much of a difference, this was a major overhaul of Shoelace&#39;s internals.&lt;/p&gt;
&lt;p&gt;Naturally, such a big change brings questions from the community, such as &lt;a href=&quot;https://twitter.com/bitflowertweets/status/1365644475087941635?s=20&quot;&gt;&amp;quot;what were the reasons behind shifting away from Stencil?&amp;quot;&lt;/a&gt; These are valid questions, so I wanted to take the time to answer them here.&lt;/p&gt;
&lt;p&gt;But before I jump in, it&#39;s worth mentioning that Stencil is a great project that played a significant role in getting me into web components. Being able to type &lt;code&gt;npm init stencil&lt;/code&gt; and have an entire project ready to go is really something special.&lt;/p&gt;
&lt;p&gt;Let it also be clear that this isn&#39;t a jab at Stencil, nor is it advice for or against using Stencil to build your own projects. This is why &lt;em&gt;I&lt;/em&gt; chose to move on based on &lt;em&gt;my&lt;/em&gt; experience, &lt;em&gt;my&lt;/em&gt; observations, and &lt;em&gt;my&lt;/em&gt; desire to own as much of my own code as possible.&lt;/p&gt;
&lt;h2 id=&quot;less-is-more&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/moving-from-stencil-to-lit-element/#less-is-more&quot;&gt;Less is more&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When you&#39;re managing a software project, dependencies can quickly become liabilities. Despite its many niceties, Stencil can be a box of mystery at times. As a contributor, it was difficult for me to dive into its codebase and figure things out. There&#39;s little documentation on its internals, so everything requires digging. A lot of digging. Even as a member of the Stencil team, I found it hard to get the information I needed to make useful contributions to the project.&lt;/p&gt;
&lt;p&gt;Why does this matter? Well, when code is complex and lacks documentation, the barrier of entry is higher and people are less apt to make contributions. Despite a tight-knit community of talented Stencil users, many bugs continue to go unpatched. Even worse, a bot &lt;a href=&quot;https://github.com/ionic-team/stencil/issues?q=is%3Aissue+label%3A%22ionitron%3A+stale+issue%22+&quot;&gt;closes issues&lt;/a&gt; after 30 days of inactivity, so many of the bugs that do get reported are &lt;a href=&quot;https://github.com/ionic-team/stencil/issues/2802&quot;&gt;closed without feedback or resolution&lt;/a&gt;. In my opinion, valid, reproducible bugs should remain open until they&#39;re resolved to provide transparency and accountability.&lt;/p&gt;
&lt;p&gt;One might surmise that the maintainers are overwhelmed by the number of bugs that get filed, but garbage collecting valid issues is disingenuous and a disservice to the community. I appreciate that Stencil is open source and its maintainers have zero responsibility to fix bugs for free, but I fundamentally disagree with this aspect of how the project is maintained.&lt;/p&gt;
&lt;p&gt;And what happens when I have an issue that I can&#39;t resolve myself? Will someone point me in the right direction? Will it ever get fixed? &lt;a href=&quot;https://github.com/ionic-team/stencil/issues/2198&quot;&gt;Probably not.&lt;/a&gt; (That was submitted a year ago, before issues were automatically closed.)&lt;/p&gt;
&lt;h2 id=&quot;build-%26-distribution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/moving-from-stencil-to-lit-element/#build-%26-distribution&quot;&gt;Build &amp;amp; distribution&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Stencil is a compiler that generates components using any number of possible &lt;a href=&quot;https://stenciljs.com/docs/output-targets&quot;&gt;output targets&lt;/a&gt;. In theory, this is really convenient because it can produce multiple distributions from a single source. In practice, I found that having two separate distributions made my project harder to document and left users confused.&lt;/p&gt;
&lt;p&gt;These output targets are also limited in terms of configuration. Since last year, Shoelace was plagued with a &lt;a href=&quot;https://github.com/shoelace-style/shoelace/issues/180&quot;&gt;tree shaking problem&lt;/a&gt; I couldn&#39;t fix because of this. Moving away from Stencil, I was able to gain full control over how my build works and the tooling used to power it. I leaned on standards and went with a single collection of &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules&quot;&gt;ES modules&lt;/a&gt; that work in both browsers and bundlers. Best of all, having full control over the build let me finally resolve that pesky tree shaking issue.&lt;/p&gt;
&lt;h2 id=&quot;less-magic&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/moving-from-stencil-to-lit-element/#less-magic&quot;&gt;Less Magic&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Speaking of distributions, one thing I&#39;m losing by leaving Stencil is its &lt;a href=&quot;https://stenciljs.com/docs/distribution&quot;&gt;lazy loading dist&lt;/a&gt;. At first, I wondered how I could reproduce this outside of Stencil. It&#39;s a very convenient feature for users.&lt;/p&gt;
&lt;p&gt;Lazy loading works by registering every component as an empty custom element. Then, when you insert a component into the DOM, its source is fetched and its internals are swapped out. This is necessary because &lt;a href=&quot;https://github.com/WICG/webcomponents/issues/829&quot;&gt;you can&#39;t reregister custom elements&lt;/a&gt;, so you have to resort to a bit of magic. It&#39;s a clever trick, but it does lead to a form of &lt;a href=&quot;https://en.wikipedia.org/wiki/Flash_of_unstyled_content&quot;&gt;FOUC&lt;/a&gt;, especially when components are added after the initial page load.&lt;/p&gt;
&lt;p&gt;I believe it was also the source of some strange Shoelace + React/Svelte timing bugs and a very annoying error I kept seeing on the documentation website:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Uncaught (in promise) DOMException: Failed to set the &#39;adoptedStyleSheets&#39; property on &#39;ShadowRoot&#39;: Sharing constructed stylesheets in multiple documents is not allowed&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I&#39;m pretty sure this was a combination of how Docsify loads pages and Stencil&#39;s lazy loading, but I was never able to pinpoint it. Regardless, it&#39;s no longer an issue with the new version.&lt;/p&gt;
&lt;p&gt;Considering all this, I thought long and hard about the benefits and drawbacks of lazy loading. Ultimately, I decided it wasn&#39;t worth the effort. With the latest version of Shoelace, users can load the &lt;a href=&quot;https://shoelace.style/getting-started/installation&quot;&gt;entire library&lt;/a&gt; or &lt;a href=&quot;https://shoelace.style/getting-started/installation?id=cherry-picking&quot;&gt;cherry pick&lt;/a&gt; components — something that wasn&#39;t possible before. I think that&#39;s a fair tradeoff to avoid all the weird issues it seemed to be causing.&lt;/p&gt;
&lt;h2 id=&quot;native-templates&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/moving-from-stencil-to-lit-element/#native-templates&quot;&gt;Native templates&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I prefer to stick to the platform when possible. Although I like JSX, I like &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals&quot;&gt;template literals&lt;/a&gt; even better because they&#39;re simple and they don&#39;t require transpilation. Now that the platform has a built-in for templating, we should utilize it.&lt;/p&gt;
&lt;p&gt;The syntax is similar, but not identical. Here&#39;s the original render function from Shoelace&#39;s badge component.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// JSX&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;span
      part&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;base&quot;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;badge&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string-property property&quot;&gt;&#39;badge--primary&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;primary&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string-property property&quot;&gt;&#39;badge--success&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;success&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string-property property&quot;&gt;&#39;badge--info&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;info&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string-property property&quot;&gt;&#39;badge--warning&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;warning&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string-property property&quot;&gt;&#39;badge--danger&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;danger&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string-property property&quot;&gt;&#39;badge--pill&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pill&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string-property property&quot;&gt;&#39;badge--pulse&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pulse
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      role&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;status&quot;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;slot &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;span&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Compare that to the native equivalent.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Template literals&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
    &amp;lt;span
      part=&quot;base&quot;
      class=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;classMap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;badge&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string-property property&quot;&gt;&#39;badge--primary&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;primary&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string-property property&quot;&gt;&#39;badge--success&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;success&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string-property property&quot;&gt;&#39;badge--info&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;info&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string-property property&quot;&gt;&#39;badge--warning&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;warning&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string-property property&quot;&gt;&#39;badge--danger&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;danger&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string-property property&quot;&gt;&#39;badge--pill&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pill&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string-property property&quot;&gt;&#39;badge--pulse&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pulse
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
      role=&quot;status&quot;
    &gt;
      &amp;lt;slot /&gt;
    &amp;lt;/span&gt;
  &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;They&#39;re so similar. I just don&#39;t see why I should run the code through another layer of transpilation when template literals suffice. This is what they were designed to do.&lt;/p&gt;
&lt;p&gt;A special syntax is no longer necessary.&lt;/p&gt;
&lt;h2 id=&quot;virtual-dom&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/moving-from-stencil-to-lit-element/#virtual-dom&quot;&gt;Virtual DOM&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Like React and other popular frameworks, Stencil uses a virtual DOM (&amp;quot;VDOM&amp;quot;) to render things faster than working directly with the real DOM. However, it&#39;s a common misconception that VDOMs are actually faster. &lt;a href=&quot;https://svelte.dev/blog/virtual-dom-is-pure-overhead&quot;&gt;Rich Harris writes:&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;But hang on a minute! The virtual DOM operations are &lt;strong&gt;in addition to&lt;/strong&gt; the eventual operations on the real DOM. The only way it could be faster is if we were comparing it to a less efficient framework (there were plenty to go around back in 2013!), or arguing against a straw man — that the alternative is to do something no-one actually does.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It&#39;s an outdated meme. You can write poor performing components with or without a virtual DOM. Consider &lt;a href=&quot;https://lit-html.polymer-project.org/&quot;&gt;lit-html&lt;/a&gt; and &lt;a href=&quot;https://github.com/WebReflection/uhtml&quot;&gt;µhtml&lt;/a&gt;, both of which leverage direct DOM diffing for fast, efficient rendering.&lt;/p&gt;
&lt;p&gt;There&#39;s no need for an extra layer here, either.&lt;/p&gt;
&lt;h2 id=&quot;a-long-time-coming&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/moving-from-stencil-to-lit-element/#a-long-time-coming&quot;&gt;A long time coming&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The move away from Stencil was inevitable. As part of my never-ending quest for simplicity, I&#39;ve been experimenting with other libraries for a long time. One of the first I explored was &lt;a href=&quot;https://hybrids.js.org/#/&quot;&gt;Hybrids&lt;/a&gt;, which is great if you want to go with a more functional approach. Ultimately, I decided that class-based made the most sense because, well, that&#39;s how you create custom elements. You can&#39;t do it without extending &lt;code&gt;HTMLElement&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;SlButton&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HTMLElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// build something awesome&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I also dove into &lt;a href=&quot;https://www.fast.design/&quot;&gt;Microsoft FAST&lt;/a&gt; and I like what they&#39;re doing. The API is very sensible, but its templates feel a bit strange since you have to use &lt;code&gt;attr=${x =&amp;gt; x.prop}&lt;/code&gt; instead of &lt;code&gt;attr=${this.prop}&lt;/code&gt;. I believe they do this to provide a faster alternative to DOM-diffing during render, but this would mean a lot more work for me. I also found it confusing that contexts can be nested, which makes larger templates harder to maintain.&lt;/p&gt;
&lt;p&gt;I experimented with my own base class called &lt;a href=&quot;https://github.com/shoelace-style/shoemaker&quot;&gt;Shoemaker&lt;/a&gt;. I wanted to make the thinnest possible abstraction around the features I needed, but the more the project evolved the more I realized I was recreating &lt;a href=&quot;https://lit-element.polymer-project.org/&quot;&gt;LitElement&lt;/a&gt;. Between that and feedback from the community, I decided it didn&#39;t make sense to reinvent the wheel.&lt;/p&gt;
&lt;p&gt;&lt;s&gt;I do have a few [opinionated] DX concerns that I&#39;ll be sending over to the LitElement team for consideration. However, I&#39;ve alleviated most of them with a handful of custom decorators.&lt;/s&gt;&lt;/p&gt;
&lt;p&gt;Jan 18, 2022: since this was written, Lit has evolved a bit and the one thing I still want from them is a &lt;code&gt;@watch&lt;/code&gt; decorator. For now, &lt;a href=&quot;https://github.com/shoelace-style/shoelace/blob/next/src/internal/watch.ts&quot;&gt;I implemented my own&lt;/a&gt;, which is something I couldn&#39;t do with Stencil.&lt;/p&gt;
&lt;h2 id=&quot;moving-forward&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/moving-from-stencil-to-lit-element/#moving-forward&quot;&gt;Moving forward&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Consumers of Shoelace won&#39;t notice much of a difference in this release. I&#39;ve simply replaced the old engine with a new one that does the same thing except with a leaner, simpler codebase with less magic. I have a responsibility to my users, so I need to be able to fix problems when they arise. I wasn&#39;t always able to do that before. Now I can.&lt;/p&gt;
&lt;p&gt;I&#39;m tired of rebuilding buttons. I designed Shoelace for longevity, taking advantage of the best parts of the platform — the stuff that doesn&#39;t change on us every few years. It only makes sense to bring its code closer to the platform as well.&lt;/p&gt;
&lt;p&gt;With LitElement, I&#39;m getting all the features I want with the smallest possible footprint. Now I can get back to building components again.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;March 8, 2021 - updated to reflect the latest changes to the library.&lt;/em&gt;&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>SVG Repo</title>
		<link href="https://www.abeautifulsite.net/posts/svg-repo/"/>
		<updated>2021-02-15T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/svg-repo/</id>
		<content type="html">&lt;p&gt;I stumbled upon a great resource for free SVGs. They&#39;re currently boasting over 300,000 images. Check it out over at &lt;a href=&quot;https://www.svgrepo.com/&quot;&gt;SVG repo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Looks like &lt;a href=&quot;https://www.fontrepo.com/&quot;&gt;they have a sister site for fonts&lt;/a&gt;, too. Lots of &#39;em.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Archiving Postleaf</title>
		<link href="https://www.abeautifulsite.net/posts/archiving-postleaf/"/>
		<updated>2021-02-03T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/archiving-postleaf/</id>
		<content type="html">&lt;p&gt;&lt;a href=&quot;https://github.com/Postleaf/postleaf&quot;&gt;Postleaf&lt;/a&gt; — at least in its current form — has been discontinued. In the future, I&#39;d like to bring it back as something different. Maybe an open source project. Maybe a SaaS product. I&#39;m not sure at this point.&lt;/p&gt;
&lt;p&gt;The world still needs a simple platform to encourage blogging and the decentralization of publishing. Unfortunately, This version of Postleaf didn&#39;t fill that gap because it was too difficult and expensive for the majority of users to install and host. Aside from that, the world of web hosting has changed significantly in recent years.&lt;/p&gt;
&lt;p&gt;For now, I&#39;m taking some time to focus on other projects and interests. I hope to revisit Postleaf again when the time is right for me, but I&#39;m not exactly sure when that might be.&lt;/p&gt;
&lt;p&gt;That said, I&#39;m archiving the Postleaf repository. Anyone is welcome to fork the project and carry the torch, but I&#39;m hanging onto the &amp;quot;Postleaf&amp;quot; name, U.S. trademark, and website, so new maintainers will need to release it under a different name.&lt;/p&gt;
&lt;p&gt;Thanks for the many years of encouragement. While my vision for Postleaf wasn&#39;t fully realized, I&#39;ve learned so much from this project and its community. I&#39;m still excited for Postleaf&#39;s future.&lt;/p&gt;
&lt;p&gt;— Cory&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Getting localized month and day names in the browser</title>
		<link href="https://www.abeautifulsite.net/posts/getting-localized-month-and-day-names-in-the-browser/"/>
		<updated>2020-11-25T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/getting-localized-month-and-day-names-in-the-browser/</id>
		<content type="html">&lt;p&gt;JavaScript has a &lt;a href=&quot;https://caniuse.com/?search=datetimeformat&quot;&gt;well-supported&lt;/a&gt; date/time formatting API called &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat&quot;&gt;&lt;code&gt;Intl.DateTimeFormat&lt;/code&gt;&lt;/a&gt;. Here&#39;s a tip — you can use it to generate localized month and day names without the need for a language pack! This is super useful if you&#39;re building, say, a date picker or a calendar app.&lt;/p&gt;
&lt;p&gt;I&#39;ve written a couple functions to demonstrate how this works. Consider them MIT licensed if you want to use them!&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getDayNames&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;locale &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;en&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; format &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;long&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; formatter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Intl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;DateTimeFormat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;locale&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;weekday&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; format&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;timeZone&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;UTC&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; days &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;day&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; dd &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; day &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;day&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; day&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;2017-01-&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;dd&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;T00:00:00+00:00&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; days&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;date&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; formatter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getMonthNames&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;locale &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;en&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; format &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;long&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; formatter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Intl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;DateTimeFormat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;locale&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;month&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; format&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;timeZone&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;UTC&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; months &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;month&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mm &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; month &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;month&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; month&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;2017-&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;mm&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;-01T00:00:00+00:00&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; months&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;date&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; formatter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each function generates a series of Date objects that align with each day of the week and each month of the year, respectively. Then they loop through each date, passing them to the browser&#39;s built-in formatter. The formatter is configured to only output the day/month name, giving us exactly what we want!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[&amp;quot;Sunday&amp;quot;, &amp;quot;Monday&amp;quot;, &amp;quot;Tuesday&amp;quot;, &amp;quot;Wednesday&amp;quot;, &amp;quot;Thursday&amp;quot;, &amp;quot;Friday&amp;quot;, &amp;quot;Saturday&amp;quot;]
[&amp;quot;January&amp;quot;, &amp;quot;February&amp;quot;, &amp;quot;March&amp;quot;, &amp;quot;April&amp;quot;, &amp;quot;May&amp;quot;, &amp;quot;June&amp;quot;, &amp;quot;July&amp;quot;, &amp;quot;August&amp;quot;, &amp;quot;September&amp;quot;, &amp;quot;October&amp;quot;, &amp;quot;November&amp;quot;, &amp;quot;December&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Need them in a different language? Just set the locale argument accordingly. Here&#39;s French, for example:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;getDayNames&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;fr&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;getMonthNames&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;fr&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// [&quot;dimanche&quot;, &quot;lundi&quot;, &quot;mardi&quot;, &quot;mercredi&quot;, &quot;jeudi&quot;, &quot;vendredi&quot;, &quot;samedi&quot;]&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// [&quot;janvier&quot;, &quot;février&quot;, &quot;mars&quot;, &quot;avril&quot;, &quot;mai&quot;, &quot;juin&quot;, &quot;juillet&quot;, &quot;août&quot;, &quot;septembre&quot;, &quot;octobre&quot;, &quot;novembre&quot;, &quot;décembre&quot;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can even generate short names by setting the format argument to &lt;code&gt;short&lt;/code&gt; or &lt;code&gt;narrow&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;getDayNames&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;en&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;short&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;getMonthNames&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;en&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;short&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// [&quot;Sun&quot;, &quot;Mon&quot;, &quot;Tue&quot;, &quot;Wed&quot;, &quot;Thu&quot;, &quot;Fri&quot;, &quot;Sat&quot;]&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// [&quot;Jan&quot;, &quot;Feb&quot;, &quot;Mar&quot;, &quot;Apr&quot;, &quot;May&quot;, &quot;Jun&quot;, &quot;Jul&quot;, &quot;Aug&quot;, &quot;Sep&quot;, &quot;Oct&quot;, &quot;Nov&quot;, &quot;Dec&quot;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While this trick may not alleviate all your i18n woes, it can certainly reduce the size of your translation packs if you&#39;re building something that uses them.&lt;/p&gt;
&lt;p&gt;And here&#39;s another tip — you can generate localized relative times such as &amp;quot;4 minutes ago&amp;quot; using a similar technique, except with &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat&quot;&gt;&lt;code&gt;Intl.RelativeTimeFormat&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Shoelace 2.0: a forward-thinking library of web components</title>
		<link href="https://www.abeautifulsite.net/posts/shoelace-a-forward-thinking-library-of-web-components/"/>
		<updated>2020-07-24T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/shoelace-a-forward-thinking-library-of-web-components/</id>
		<content type="html">&lt;p&gt;I&#39;ve been having a lot of fun with &lt;a href=&quot;https://stenciljs.com/&quot;&gt;Stencil&lt;/a&gt; and web components lately. Back in January, I decided to use it to completely redesign &lt;a href=&quot;https://shoelace.style/&quot;&gt;Shoelace&lt;/a&gt;, an open source project I created a few years ago.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/shoelace-2-splash.png&quot; alt=&quot;Screenshot of the Shoelace 2 logo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I recently published &lt;a href=&quot;https://shoelace.style/&quot;&gt;Shoelace 2.0&lt;/a&gt; — a collection of professionally-designed, accessible web components.&lt;/p&gt;
&lt;p&gt;One really nice feature of web components is that &lt;strong&gt;you can use them with any framework&lt;/strong&gt;. This is an amazing concept, especially for low-level building block components.&lt;/p&gt;
&lt;p&gt;Let me explain why this is so amazing with an example.&lt;/p&gt;
&lt;p&gt;Imagine you&#39;re on one of three teams in an organization, all tasked with building a different product. Team 1 wants to use React, Team 2 wants to use Vue, and Team 3 wants to use vanilla HTML+JS. The one requirement you have from your organization is that the UX must be consistent across all three products.&lt;/p&gt;
&lt;p&gt;Obviously, sharing a library of UI components between the projects is the most efficient way to meet that requirement. But if you build your components in Framework A, you can&#39;t reuse them in Framework B or Framework C.&lt;/p&gt;
&lt;p&gt;Web components solve this problem. They&#39;re &lt;a href=&quot;https://caniuse.com/#feat=custom-elementsv1&quot;&gt;supported by all modern browsers&lt;/a&gt;, they&#39;re framework-agnostic, and they&#39;re &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Web_Components&quot;&gt;built into the standard&lt;/a&gt;, so we know they&#39;ll be supported for many years to come.&lt;/p&gt;
&lt;p&gt;This is the technology that Shoelace is built on.&lt;/p&gt;
&lt;h2 id=&quot;%22but-i-only-use-%5Binsert-your-favorite-framework-here%5D!%22&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/shoelace-a-forward-thinking-library-of-web-components/#%22but-i-only-use-%5Binsert-your-favorite-framework-here%5D!%22&quot;&gt;&amp;quot;But I only use [insert your favorite framework here]!&amp;quot;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I hear you. You &lt;em&gt;only&lt;/em&gt; use React/Vue/Angular/whatever, so why should you care if your components work in other frameworks?&lt;/p&gt;
&lt;p&gt;The fact is, at some point your beloved framework will ship a new version with breaking changes, and when that happens, you&#39;ll be reworking every button, input, dialog, dropdown, tab group, etc. That&#39;s just how software works.&lt;/p&gt;
&lt;p&gt;And further down the road, your framework of choice won&#39;t be as ubiquitous as it is today. Things change and, like it or not, you will eventually move on or get left behind.&lt;/p&gt;
&lt;p&gt;Since Shoelace is built on standardized browser APIs, it will be around long after today&#39;s most popular frameworks become obsolete.&lt;/p&gt;
&lt;h2 id=&quot;tl%3Bdr&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/shoelace-a-forward-thinking-library-of-web-components/#tl%3Bdr&quot;&gt;TL;DR&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I love building UI components, but it really sucks to rebuild them for every new framework (and new framework version). With Shoelace, I&#39;m harnessing the power of web components to bring you a reusable, customizable component library that works with whatever framework you&#39;re using today and whatever framework you&#39;ll be using tomorrow.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://shoelace.style/&quot;&gt;Check it out at shoelace.style&lt;/a&gt;&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Cory&#39;s amazing dot paper</title>
		<link href="https://www.abeautifulsite.net/posts/corys-amazing-dot-paper/"/>
		<updated>2019-06-03T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/corys-amazing-dot-paper/</id>
		<content type="html">&lt;p&gt;In a world where designers use Sketch, Photoshop, and other apps to create wireframes, I&#39;m here in my corner holding this old fashioned pencil and a stack of dot paper.&lt;/p&gt;
&lt;p&gt;Sorry, but for me, these primitive tools do the same thing and I find them easier to use.&lt;/p&gt;
&lt;p&gt;I don&#39;t know. I guess it&#39;s just faster to grab a pencil and paper to transform my thoughts into a wireframe. I also use it for jotting down notes and todos here and there. In fact, aside from GitHub issues, I don&#39;t even have a task manager.&lt;/p&gt;
&lt;p&gt;I used to use lined paper, but that&#39;s distracting. Then I tried graph paper, which was better but still a bit distracting. At some point, I discovered dot paper, but it&#39;s incredibly hard to find and usually expensive.&lt;/p&gt;
&lt;p&gt;So I created my own.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/corys-dot-paper.jpg&quot; alt=&quot;A small stack of dot paper on top of a wooden desk with a mechanical pencil on top&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The dots are intentionally subtle to minimize distraction. I usually print out 20 sheets at a time and use a binder clip to keep them together. A good mechanical pencil is a necessity since it never needs to be sharpened and keeps a consistent edge.&lt;/p&gt;
&lt;p&gt;This is the same paper I used to draw wireframes for my &lt;a href=&quot;https://www.abeautifulsite.net/posts/a-free-html-css-and-js-beautifier/&quot;&gt;free HTML, CSS, and JS beautifier&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Today, I&#39;m releasing my homegrown dot paper for free in two variations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.abeautifulsite.net/downloads/dot-paper/dot-paper.pdf&quot;&gt;Dot paper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.abeautifulsite.net/downloads/dot-paper/dot-paper-grid.pdf&quot;&gt;Dot paper with grid&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The version with grid is excellent for wireframes, as it provides a way to measure without counting dots.&lt;/p&gt;
&lt;p&gt;Just download, print, and start creating!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>A free HTML, CSS, and JavaScript beautifier</title>
		<link href="https://www.abeautifulsite.net/posts/a-free-html-css-and-js-beautifier/"/>
		<updated>2019-05-22T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/a-free-html-css-and-js-beautifier/</id>
		<content type="html">&lt;p&gt;Ten years ago, I launched &lt;a href=&quot;https://dirtymarkup.com/&quot;&gt;DirtyMarkup&lt;/a&gt; to clean up dirty code. It was a fun little tool, but its best feature was that it was easy to use and didn&#39;t have intrusive advertisements.&lt;/p&gt;
&lt;p&gt;I sold DirtyMarkup a couple years ago, and since then the new owners slapped on a header that makes the page scroll and some banner ads. 😒&lt;/p&gt;
&lt;p&gt;I missed having my own tool, so last week I built a new one from scratch that’s even better. 💪&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/beautifier-wireframe.jpg&quot; alt=&quot;Picture of a hand-drawn wireframe of my new tool&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You can find it at: &lt;a href=&quot;https://www.surrealcms.com/beautify&quot;&gt;surrealcms.com/beautify&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The new tool doesn’t use Tidy. Instead, it relies on &lt;a href=&quot;https://prettier.io/&quot;&gt;Prettier&lt;/a&gt; for cleaning up HTML, CSS, and JavaScript code. That means it doesn’t require a binary and the results are instant.&lt;/p&gt;
&lt;p&gt;If you’re interested in how I built it, &lt;a href=&quot;https://www.surrealcms.com/blog/creating-a-code-beautifier-in-two-days.html&quot;&gt;I posted a write-up here&lt;/a&gt;.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Let&#39;s Encrypt renews but browsers still seeing old/expired SSL certificate</title>
		<link href="https://www.abeautifulsite.net/posts/lets-encrypt-renews-but-browsers-still-seeing-oldexpired-ssl-certificate/"/>
		<updated>2019-05-10T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/lets-encrypt-renews-but-browsers-still-seeing-oldexpired-ssl-certificate/</id>
		<content type="html">&lt;p&gt;This morning was frustrating. I recently upgraded my VPS from the deprecated &lt;code&gt;letsencrypt&lt;/code&gt; client to the newer &lt;code&gt;cerbot&lt;/code&gt; client and generated new certificates for all my personal domains. I thought everything was fine — until I kept seeing intermittent SSL errors.&lt;/p&gt;
&lt;p&gt;I figured I did something wrong, so I triple checked my Apache configs, made sure each website was pointing to the correct certificate, and restarted Apache...things seemed to work in Chrome, but not Firefox.&lt;/p&gt;
&lt;p&gt;Ok, obviously Firefox was caching the certificate, right? I cleared everything. Same error. I reinstalled Firefox. Same error. Then I noticed that, when I refreshed Chrome, I would &lt;em&gt;occasionally&lt;/em&gt; see images blocked, then a moment later they would load.&lt;/p&gt;
&lt;p&gt;I ran some SSL tests with mixed results. They were seeing both certs intermittently too. 🤔&lt;/p&gt;
&lt;p&gt;So I disabled the server with &lt;code&gt;sudo service apache2 stop&lt;/code&gt;. To my surprise, my websites were online, but this time the SSL was consistently invalid.&lt;/p&gt;
&lt;p&gt;It turns out, when I upgraded to &lt;code&gt;certbot&lt;/code&gt;, I somehow launched a second instance Apache that wasn&#39;t responding to reloads, so there were two instances handling HTTPS traffic — one serving up the cached certificate from memory.&lt;/p&gt;
&lt;p&gt;To solve the problem, I ran:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;killall&lt;/span&gt; apache2
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;service&lt;/span&gt; apache2 start&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Evidently, Chrome is more resilient to this than Firefox. Perhaps when Chrome sees a valid certificate from at least one HTTPS request, it retries any that fail until it gets a valid one.&lt;/p&gt;
&lt;p&gt;Either way, mystery solved. 🕵🏻‍♂️&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Introducing Surreal CMS 7</title>
		<link href="https://www.abeautifulsite.net/posts/introducing-surreal-cms-7/"/>
		<updated>2019-04-26T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/introducing-surreal-cms-7/</id>
		<content type="html">&lt;p&gt;Last November was the 10 year mark for &lt;a href=&quot;https://www.surrealcms.com/&quot;&gt;Surreal CMS&lt;/a&gt;, a content management service I created to manage static (and mostly static) websites.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/surreal-cms-7-homepage.png&quot; alt=&quot;Screenshot of the Surreal CMS 7 homepage&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Last week, &lt;a href=&quot;https://www.surrealcms.com/blog/announcing-surreal-cms-7.html&quot;&gt;I soft launched Surreal CMS 7&lt;/a&gt;. This new version is a complete rebuild from scratch using Node.js + Vue.js. I worked on this new app for a long time, and I&#39;m incredibly happy with the result.&lt;/p&gt;
&lt;p&gt;Everything has been improved in this version, and there&#39;s a bunch of great new features that really make static websites fun to manage. Early feedback from new and existing users has been overwhelmingly positive!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I&#39;ve also reintroduced the free plan&lt;/strong&gt; for personal, educational, and non-profit users!&lt;/p&gt;
&lt;p&gt;The list of updates and improvements is way too long to list here, but you can check out the &lt;a href=&quot;https://www.surrealcms.com/blog/announcing-surreal-cms-7.html&quot;&gt;official announcement&lt;/a&gt; to learn more.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Getting duplicate ids in an HTML document</title>
		<link href="https://www.abeautifulsite.net/posts/getting-duplicate-ids-in-an-html-document/"/>
		<updated>2019-04-05T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/getting-duplicate-ids-in-an-html-document/</id>
		<content type="html">&lt;p&gt;I needed a way to identify all HTML elements with duplicate IDs. This is a seemingly simple task, but unfortunately, I didn&#39;t find anything out there that fit the bill.&lt;/p&gt;
&lt;p&gt;I did find a couple functions that returned the duplicates, but they didn&#39;t include the first occurrence (I guess they assume the first occurrence isn&#39;t a duplicate, but all subsequent occurrences are).&lt;/p&gt;
&lt;p&gt;So here&#39;s a function that does the job.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getAllDuplicateIds&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; elements &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;[id]&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ids &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; elements&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;el&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; el&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; dups &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; elements&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;el&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; ids&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; id &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; el&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
  
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; dups&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This function will return an array of elements in the document that have duplicate IDs. If no duplicates are found, an empty array is returned.&lt;/p&gt;
&lt;p&gt;If you only need all occurrences &lt;em&gt;after&lt;/em&gt; the first, here&#39;s a similar ES6 function for that, too.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getDuplicateIds&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  
 &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; elements &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;[id]&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
 &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ids &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
 &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; dups &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
   
 elements&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;el&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; ids&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;el&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; dups&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;el&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ids&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;el&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
   
 &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; dups&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content>
	</entry>
	
	<entry>
		<title>A clever way to style the &lt;mark&gt; element</title>
		<link href="https://www.abeautifulsite.net/posts/a-clever-way-to-style-the-mark-element/"/>
		<updated>2019-02-01T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/a-clever-way-to-style-the-mark-element/</id>
		<content type="html">&lt;p&gt;I was checking out the &lt;a href=&quot;https://cashnotify.com/&quot;&gt;CashNotify app&lt;/a&gt; today and I noticed a beautiful style for highlighting text in their testimonials:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/styling-mark-1.png&quot; alt=&quot;Screenshot of text highlighted with a fancy style&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Most textual highlights use a boring rectangle background color, but this stands out and looks gorgeous. I was really hoping they were using a simple &lt;code&gt;&amp;lt;mark&amp;gt;&lt;/code&gt; tag to accomplish this and was happy to learn that they are. The markup is as simple as it could be:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;Just &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;mark&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;highlight&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;mark&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; it!&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the styles are simple too:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;mark&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;linear-gradient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;-100deg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hsla&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;48&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;92%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;75%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;.3&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hsla&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;48&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;92%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;75%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;.7&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 95%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hsla&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;48&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;92%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;75%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;.1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1em 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; .5rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/styling-mark-2.png&quot; alt=&quot;Another screenshot of text highlighted with a fancy style&quot; /&gt;&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Opening a new window after an async operation</title>
		<link href="https://www.abeautifulsite.net/posts/opening-a-new-window-after-an-async-operation/"/>
		<updated>2018-08-28T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/opening-a-new-window-after-an-async-operation/</id>
		<content type="html">&lt;p&gt;I was working on an OAuth implementation the other day and needed to open a third-party auth page in a new window.&lt;/p&gt;
&lt;p&gt;However, I needed to fetch the target URL from the server first, then open the window. Kinda like this:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; button &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;auth-button&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
button&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;click&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;getAuthUrl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, this doesn&#39;t work in most browsers — the popup gets blocked because the window wasn&#39;t opened immediately after the click.&lt;/p&gt;
&lt;p&gt;To work around this, we need to open the window immediately after the click, so let&#39;s use the well-supported about:blank URL to our advantage.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; button &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;auth-button&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
button&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;click&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; win &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;about:blank&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;getAuthUrl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    win&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;location &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now the window opens and redirects to the appropriate URL after the async function executes!&lt;/p&gt;
&lt;p&gt;You can take it a step further by opening a special page that shows a loader instead. Just swap out about:blank with your own page.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Zipping multiple folders into separate zip files</title>
		<link href="https://www.abeautifulsite.net/posts/zipping-multiple-folders-into-separate-zip-files/"/>
		<updated>2017-07-31T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/zipping-multiple-folders-into-separate-zip-files/</id>
		<content type="html">&lt;p&gt;Here&#39;s a bash script that will zip all folders in the current directory into separate &lt;code&gt;.zip&lt;/code&gt; files:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token for-or-select variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; */&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;zip&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-r&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;${i&lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;}&lt;/span&gt;.zip&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$i&lt;/span&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;done&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I had to do this to 75+ folders today and this definitely saved me some time. It works on macOS too!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Shoelace.style — A back to the basics CSS starter kit</title>
		<link href="https://www.abeautifulsite.net/posts/shoelacecss-a-back-to-the-basics-css-starter-kit/"/>
		<updated>2017-07-27T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/shoelacecss-a-back-to-the-basics-css-starter-kit/</id>
		<content type="html">&lt;p&gt;I spent some time last week working on a free CSS boilerplate I&#39;m calling &lt;a href=&quot;https://shoelace.style/&quot;&gt;Shoelace.css&lt;/a&gt;. It&#39;s kinda like Bootstrap, but a lot leaner and pure CSS. You don&#39;t need a preprocessor like Sass or Less to use it, but it&#39;s still highly customizable with &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables&quot;&gt;CSS variables&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&#39;m calling Shoelace a &amp;quot;starter kit&amp;quot;, not a framework. The goal was to create a lightweight, fully customizable, and extensible boilerplate for building websites and web apps.&lt;/p&gt;
&lt;p&gt;What makes Shoelace really awesome is that you can &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; to it with just one line of code and start using it. Customizations can be made in your own stylesheet by simply overriding variables:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;:root&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;--body-bg-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; black&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;--body-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; white&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Shoelace is only ~31KB minified and comes in at about 7.9KB gzipped. For comparison, Bootstrap 4 alpha 6 is 192KB CSS + 47KB JavaScript. And, starting today, you can use Shoelace via CDN courtesy of &lt;a href=&quot;https://www.keycdn.com/&quot;&gt;KeyCDN&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For more info and to grab the source, head over to &lt;a href=&quot;https://shoelace.style/&quot;&gt;shoelace.style&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;July 24, 2020: Shoelace 2.0 has been released. The library has become a collection of professionally-designed web components and is much different than the original version.&lt;/em&gt;&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Downloading a list of URLs automatically</title>
		<link href="https://www.abeautifulsite.net/posts/downloading-a-list-of-urls-automatically/"/>
		<updated>2017-07-21T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/downloading-a-list-of-urls-automatically/</id>
		<content type="html">&lt;p&gt;I recently needed to download a bunch of files from Amazon S3, but I didn&#39;t have direct access to the bucket — I only had a list of URLs.&lt;/p&gt;
&lt;p&gt;There were too many to fetch one by one, so I wanted to fetch them automatically. Here are a couple ways I found to do that.&lt;/p&gt;
&lt;h2 id=&quot;using-curl&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/downloading-a-list-of-urls-automatically/#using-curl&quot;&gt;Using curl&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Curl comes installed on every Mac and just about every Linux distro, so it was my first choice for this task. Turns out it&#39;s pretty easy.&lt;/p&gt;
&lt;p&gt;Create a new file called &lt;code&gt;files.txt&lt;/code&gt; and paste the URLs one per line. Then run the following command.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;xargs&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-n&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-O&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; files.txt&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Curl will download each and every file into the current directory.&lt;/p&gt;
&lt;h2 id=&quot;using-wget&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/downloading-a-list-of-urls-automatically/#using-wget&quot;&gt;Using wget&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;re on Linux or curl isn&#39;t available for some reason, you can do the same thing with wget.&lt;/p&gt;
&lt;p&gt;Create a new file called &lt;code&gt;files.txt&lt;/code&gt; and paste the URLs one per line. Then run the following command:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;wget&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt; files.txt&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Wget will download each and every file into the current directory.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tip for macOS users:&lt;/strong&gt; If you want to use wget on macOS, you can install it via &lt;a href=&quot;https://brew.sh/&quot;&gt;Homebrew&lt;/a&gt; using &lt;code&gt;homebrew install wget&lt;/code&gt;.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Surreal CMS acquires PageLime</title>
		<link href="https://www.abeautifulsite.net/posts/surreal-cms-acquires-pagelime/"/>
		<updated>2017-07-14T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/surreal-cms-acquires-pagelime/</id>
		<content type="html">&lt;p&gt;Nearly a decade ago, I launched my first SaaS application. It was a new take on content management — a hosted CMS that reads/writes directly to a web server and uses class attributes to define content regions.&lt;/p&gt;
&lt;p&gt;It was a great idea. Such a great idea that it inspired others to do the same. One of those apps was called PageLime.&lt;/p&gt;
&lt;p&gt;Over the years, I&#39;ve seen a number of similar services come and go, but PageLime came out swinging. These guys had tons of energy. Hell, they even managed to get &lt;a href=&quot;http://mashable.com/2010/12/31/pagelime-cms/&quot;&gt;featured by Mashable in 2010&lt;/a&gt;. It was the first time I was actually worried about my competition.&lt;/p&gt;
&lt;p&gt;I never imagined that seven years later I would acquire them.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/pagelime-backdrop.png&quot; alt=&quot;A decorative backdrop used by the original PageLime website&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-happened%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/surreal-cms-acquires-pagelime/#what-happened%3F&quot;&gt;What happened?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;About three years ago, I noticed PageLime&#39;s support starting to slip. This was evidenced by users&#39; feedback on Twitter and emails from new Surreal CMS users that were coming from PageLime.&lt;/p&gt;
&lt;p&gt;Turns out, for whatever reason, PageLime&#39;s founders had moved on to other businesses and someone new had taken over support.&lt;/p&gt;
&lt;p&gt;Since then, PageLime remained stagnant. Development stopped. The forum went offline. Then the blog was taken down. Sure, the website and service were still online, but they were just kinda there.&lt;/p&gt;
&lt;h2 id=&quot;down-for-a-week&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/surreal-cms-acquires-pagelime/#down-for-a-week&quot;&gt;Down for a week&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;On May 25, 2017, Twitter users began reporting that &lt;a href=&quot;https://twitter.com/karenzadesign/status/869266717108834305&quot;&gt;PageLime was down&lt;/a&gt;. Sure enough it was, and it stayed down until June 2 with no official response from support.&lt;/p&gt;
&lt;p&gt;I can only speculate as to what happened. I don&#39;t know why it took so long to get the service back online. It was upsetting to users, for sure, but it also upset me as a SaaS owner who takes pride in offering &lt;a href=&quot;https://x.com/claviska/status/869614153828315136&quot;&gt;top notch support&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-acquisition&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/surreal-cms-acquires-pagelime/#the-acquisition&quot;&gt;The acquisition&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In early June, one of PageLime&#39;s co-founders contacted me about sunsetting the service. I outlined my vision for migrating users to Surreal CMS and we eventually came to an agreement for acquisition. (Details of the acquisition will remain private as part of the agreement.)&lt;/p&gt;
&lt;p&gt;Over the last few weeks, I&#39;ve worked diligently to create a tool that helps PageLime users migrate their account to Surreal CMS. My goal was to make the transition as seamless as possible for everyone.&lt;/p&gt;
&lt;p&gt;Starting today, you can migrate your PageLime account to Surreal CMS in just a few seconds with the automated migration tool available on PageLime&#39;s website.&lt;/p&gt;
&lt;h2 id=&quot;the-shutdown&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/surreal-cms-acquires-pagelime/#the-shutdown&quot;&gt;The shutdown&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;PageLime will officially shutdown on August 31, 2017.&lt;/p&gt;
&lt;p&gt;To be clear, I didn&#39;t acquire PageLime to shut it down — that was already going to happen. I acquired it to offer users a seamless transition from one service to another, and Surreal CMS is undoubtedly the most qualified alternative for them.&lt;/p&gt;
&lt;p&gt;Of course, the migration is completely opt-in. Users can decide if they want to migrate their accounts to Surreal CMS or seek another service. Those who do migrate will receive two weeks free to make sure Surreal CMS is a good fit for their business.&lt;/p&gt;
&lt;p&gt;I encourage PageLime users to join the &lt;a href=&quot;https://community.surrealcms.com/&quot;&gt;Surreal CMS community forum&lt;/a&gt;. It&#39;s a great place to ask questions, meet fellow designers, and show the community what you&#39;ve been working on.&lt;/p&gt;
&lt;p&gt;If you have questions about your PageLime account or the acquisition, please visit &lt;a href=&quot;http://pagelime.com/&quot;&gt;pagelime.com&lt;/a&gt;. If you need to talk to a human, there&#39;s a link on the homepage.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Rebuilding your Spotlight index in macOS</title>
		<link href="https://www.abeautifulsite.net/posts/rebuilding-your-spotlight-index-in-macos/"/>
		<updated>2017-07-14T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/rebuilding-your-spotlight-index-in-macos/</id>
		<content type="html">&lt;p&gt;I use Spotlight more than I like to admit, usually for launching apps. Recently, some of my apps and files stopped appearing — even ones I access frequently.&lt;/p&gt;
&lt;p&gt;After sifting through numerous posts online, I finally discovered one that seems to work. Running this command in the terminal seems to do the trick:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; mdutil &lt;span class=&quot;token parameter variable&quot;&gt;-E&lt;/span&gt; /&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you&#39;re having problem with just a certain disk, you can replace &lt;code&gt;/&lt;/code&gt; with the appropriate device name (tip: drag the device into the terminal and let macOS input it for you).&lt;/p&gt;
&lt;p&gt;Finally, my Spotlight is back to normal!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Thoughts on AMP</title>
		<link href="https://www.abeautifulsite.net/posts/thoughts-on-amp/"/>
		<updated>2017-05-23T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/thoughts-on-amp/</id>
		<content type="html">&lt;p&gt;Some time ago, a user asked about &lt;a href=&quot;https://www.ampproject.org/&quot;&gt;Google AMP&lt;/a&gt; support. At the time, I didn&#39;t know much about AMP aside from it made pages load faster on mobile devices. It sounded neat.&lt;/p&gt;
&lt;p&gt;A couple weeks ago, I decided to dive in and integrate AMP with Postleaf. But the deeper I got, the more I realized exactly how it works and why it&#39;s terrible for the web.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/postleafapp/status/863123916126081029&quot;&gt;I went on a Twitter rant&lt;/a&gt; about some of the issues I encountered, but I think it will be better to highlight &lt;em&gt;why&lt;/em&gt; it&#39;s such a bad idea and why I ultimately chose not to add AMP in Postleaf. I&#39;m sure I&#39;ll be linking people to this post in the future.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; – AMP is parading around as an open-source initiative that makes the web faster for mobile users, but it&#39;s really just Google&#39;s way of locking users into their own ecosystem.&lt;/p&gt;
&lt;h2 id=&quot;the-spec&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/thoughts-on-amp/#the-spec&quot;&gt;The spec&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;First off, the AMP spec is way too strict:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You must include &lt;a href=&quot;https://www.ampproject.org/docs/tutorials/create/basic_markup&quot;&gt;this exact style block&lt;/a&gt; on every page&lt;/li&gt;
&lt;li&gt;The first child element in your &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; tag must be a meta tag specifying UTF-8 encoding&lt;/li&gt;
&lt;li&gt;The second child element must be the AMP script&lt;/li&gt;
&lt;li&gt;You must include a viewport tag with a specific value&lt;/li&gt;
&lt;li&gt;You must put all your custom styles on the page using a &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; block&lt;/li&gt;
&lt;li&gt;You must not use &lt;a href=&quot;https://www.ampproject.org/docs/guides/responsive/style_pages#disallowed-styles&quot;&gt;restricted CSS properties&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;You must not use scripts&lt;/li&gt;
&lt;li&gt;You must convert certain HTML tags (such as &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt;) to AMP-compatible tags&lt;/li&gt;
&lt;li&gt;You must convert embedded content to AMP compatible components in order for them to render&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.ampproject.org/docs/tutorials/create/basic_markup&quot;&gt;The list goes on&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I understand the reason behind some of these requirements, but I disagree with many of them and the overall implementation. As a web developer and publisher, I find it inconvenient and unnecessarily restrictive. This isn&#39;t how the web is supposed to be.&lt;/p&gt;
&lt;h2 id=&quot;components&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/thoughts-on-amp/#components&quot;&gt;Components&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While experimenting, I couldn&#39;t get a single &lt;code&gt;&amp;lt;amp-iframe&amp;gt;&lt;/code&gt; to load without an error. For all embed providers I tested, the iframe rendered as an empty box. Turns out, the correct way to embed third-party content is with &lt;a href=&quot;https://ampbyexample.com/#components&quot;&gt;custom AMP components&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But guess what? If your content incorporates HTML from a third-party website (e.g. via copy &amp;amp; paste or oEmbed), there&#39;s virtually no way to convert it to an AMP-compatible component. The spec seems to assume your CMS will be aware of the embedded content&#39;s provider, but that isn&#39;t always true.&lt;/p&gt;
&lt;p&gt;Furthermore, AMP doesn&#39;t have components for all content providers. You&#39;re stuck using &lt;a href=&quot;https://ampbyexample.com/#components&quot;&gt;the ones they want you to use&lt;/a&gt;. I&#39;ll say it again: this isn&#39;t how the web is supposed to be.&lt;/p&gt;
&lt;h2 id=&quot;no-scripts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/thoughts-on-amp/#no-scripts&quot;&gt;No scripts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This isn&#39;t necessarily a bad thing, but it has a terrible side effect. On one hand, you&#39;ll never seeing those annoying popover ads on an AMP page. On the other, you&#39;re not allowed to use any scripts. At all.&lt;/p&gt;
&lt;p&gt;Want a custom nav menu? Sorry, you have to use the &lt;a href=&quot;https://ampbyexample.com/components/amp-sidebar/&quot;&gt;AMP sidebar&lt;/a&gt;. Want to build a carousel? Nope, you have to use the &lt;a href=&quot;https://ampbyexample.com/components/amp-carousel/&quot;&gt;AMP carousel&lt;/a&gt;. Want a custom widget that AMP doesn&#39;t support? Nope, too bad.&lt;/p&gt;
&lt;p&gt;If it hasn&#39;t become clear by now, AMP is about more than making your pages load faster. It&#39;s about locking users into Google&#39;s ecosystem.&lt;/p&gt;
&lt;h2 id=&quot;a-closed-portal&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/thoughts-on-amp/#a-closed-portal&quot;&gt;A closed portal&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It may sound like a conspiracy theory, but I&#39;m not the only one who feels this way. &lt;a href=&quot;https://danielmiessler.com/blog/google-amp-not-good-thing/&quot;&gt;Daniel Miessler writes:&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[AMP is] a technology that makes mobile page results load very quickly on Google, it displays the content in a more uniform fashion. But there’s a problem.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The content loads off of Google’s own server, not from the website itself.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Think about that. By creating an AMP version of your content, you&#39;re effectively publishing it to Google&#39;s server and giving them permission to do pretty much whatever they want with it.&lt;/p&gt;
&lt;p&gt;Daniel continues:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It’s poisonous to the underlying concept of an open internet.&lt;/p&gt;
&lt;p&gt;If this were to become widely adopted, you’d search for something, get results, consume the content, and you’d never leave Google.&lt;/p&gt;
&lt;p&gt;They want to be a portal, in other words. A portal that you never leave. And this is coming from the most successful and profitable advertising company in the world.&lt;/p&gt;
&lt;p&gt;Who (other than Google) can possibly see this as a good thing?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Exactly. &lt;a href=&quot;https://www.ampproject.org/&quot;&gt;Their homepage&lt;/a&gt; claims that AMP is &amp;quot;an open-source initiative aiming to make the web better for all,&amp;quot; but AMP isn&#39;t a good thing for anyone except Google. &lt;a href=&quot;https://www.theregister.co.uk/2017/05/19/open_source_insider_google_amp_bad_bad_bad/&quot;&gt;According to Scott Gilbertson&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;So it&#39;s not really about speed. As with anything that eschews standards for its own modified version thereof, it&#39;s about lock-in. Tons of pages in Google AMP markup mean tons of pages that are optimized specifically for Google and indexed primarily by Google and shown primarily to Google users. It&#39;s Google&#39;s attempt to match Facebook&#39;s platform. And yes, Facebook is far worse than AMP, but that doesn&#39;t make Google AMP a good idea. At least Facebook doesn&#39;t try to pretend like it&#39;s open.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That&#39;s perhaps the worst part. Google has gone out of its way to make AMP seem like an open-source initiative, but the intention is anything but.&lt;/p&gt;
&lt;p&gt;Also concerning is &lt;a href=&quot;https://80x24.net/post/the-problem-with-amp/&quot;&gt;this post by Kyle Schreiber&lt;/a&gt; that discusses Google&#39;s governance policy over AMP:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Google has the ability to further change the AMP HTML specification to keep publishers in their ecosystem. Google already makes deleting AMP pages difficult. Despite touting AMP HTML as an open standard, every one of the AMP Project’s core developers appears to be a Google employee.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That doesn&#39;t sound nearly as open as their homepage claims.&lt;/p&gt;
&lt;h2 id=&quot;decentralized-publishing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/thoughts-on-amp/#decentralized-publishing&quot;&gt;Decentralized Publishing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of Postleaf&#39;s founding principles revolves around a decentralized publishing experience. I believe this software should be open and free, just like the web is. &lt;em&gt;Just like the web was intended.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You and only you should own and control your content. It&#39;s that simple.&lt;/p&gt;
&lt;p&gt;Supporting Google AMP would go against this fundamental belief. It&#39;s something I feel very strongly about and it&#39;s something I&#39;ve worked hard to instill into Postleaf.&lt;/p&gt;
&lt;p&gt;The truth is, if you really want your pages to load fast, you don&#39;t need AMP. Take it from &lt;a href=&quot;https://daringfireball.net/linked/2017/05/20/gilbertson-amp&quot;&gt;John Gruber&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Yes, AMP pages load fast, but you don’t need AMP for fast-loading web pages. If you are a publisher and your web pages don’t load fast, the sane solution is to &lt;a href=&quot;http://idlewords.com/amp_static.html&quot;&gt;fix your fucking website so that pages load fast&lt;/a&gt;, not to throw your hands up in the air and implement AMP.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Or, summed up in a tweet by yours truly:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Problem: your website doesn&#39;t load fast.&lt;/p&gt;
&lt;p&gt;Solution: optimize, remove cruft, ditch 20+ analytics scripts, don&#39;t serve page-blocking ads.&lt;/p&gt;
&lt;p&gt;— Postleaf (@postleafapp) &lt;a href=&quot;https://twitter.com/postleafapp/status/866086420703784960&quot;&gt;May 21, 2017&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That said, I think it&#39;s pretty obvious I won&#39;t be adding support for AMP in Postleaf anytime soon.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>JSON Feed</title>
		<link href="https://www.abeautifulsite.net/posts/json-feed/"/>
		<updated>2017-05-23T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/json-feed/</id>
		<content type="html">&lt;p&gt;&lt;a href=&quot;https://jsonfeed.org/&quot;&gt;JSON Feed&lt;/a&gt; is a lot like RSS, except instead of XML it&#39;s formatted with JSON. It&#39;s a rather new spec, &lt;a href=&quot;https://jsonfeed.org/2017/05/17/announcing_json_feed&quot;&gt;introduced just last week&lt;/a&gt;, but it&#39;s been getting some &lt;a href=&quot;https://daringfireball.net/linked/2017/05/18/maxime-vaillancourt-json-feed-viewer&quot;&gt;major coverage&lt;/a&gt; and a number of applications have already started supporting it.&lt;/p&gt;
&lt;p&gt;Since Postleaf was built for the modern publisher, I decided to add support for it in alpha 5. It&#39;s just like &lt;a href=&quot;https://daringfireball.net/linked/2017/05/23/json-feed-dr-drang&quot;&gt;John Gruber says&lt;/a&gt;, &amp;quot;easier to generate, easier to parse.&amp;quot;&lt;/p&gt;
&lt;p&gt;I expect to see a lot about JSON Feed in the coming months. I&#39;m even happier to report that, within days of the spec being released, Postleaf is well-prepared!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Postleaf: reimagined</title>
		<link href="https://www.abeautifulsite.net/posts/postleaf-reimagined/"/>
		<updated>2017-04-26T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/postleaf-reimagined/</id>
		<content type="html">&lt;p&gt;It&#39;s been about nine months since Postleaf debuted as a simple, beautiful, open source, PHP blogging platform. The initial version was well-received, landing &lt;a href=&quot;https://techcrunch.com/2016/08/23/postleaf-is-a-open-source-blogging-platform-for-the-design-conscious/&quot;&gt;an article on TechCrunch&lt;/a&gt; and making its way to &lt;a href=&quot;https://www.producthunt.com/posts/postleaf&quot;&gt;#1 for the day on Product Hunt&lt;/a&gt;. (Thank you so much, everyone!)&lt;/p&gt;
&lt;p&gt;Today, I&#39;m announcing something pretty big: &lt;em&gt;A complete redesign, a new platform, and some amazing new features.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/postleaf-posts.png&quot; alt=&quot;Screenshot of the new Postleaf dashboard&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;from-the-ground-up&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/postleaf-reimagined/#from-the-ground-up&quot;&gt;From the Ground Up&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Postleaf has been redesigned from the ground up. I&#39;ve moved the project to Node.js, refined the user interface, and added a number of incredible features that just work:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Inline editing&lt;/li&gt;
&lt;li&gt;Distraction-free (&amp;quot;zen&amp;quot;) mode with day and night support&lt;/li&gt;
&lt;li&gt;Automatic responsive images via Dynamic Images&lt;/li&gt;
&lt;li&gt;Themes via Dust.js&lt;/li&gt;
&lt;li&gt;Fast, database-agnostic built-in search&lt;/li&gt;
&lt;li&gt;Integrated file manager&lt;/li&gt;
&lt;li&gt;Out of the box support for JSON-LD, OpenGraph, and Twitter Cards&lt;/li&gt;
&lt;li&gt;oEmbed support for embedding third-party content&lt;/li&gt;
&lt;li&gt;Spotlight-style search from anywhere in the admin panel&lt;/li&gt;
&lt;li&gt;Simple backups (including content as easy-to-read JSON files, themes, and uploads in a single zip file)&lt;/li&gt;
&lt;li&gt;Custom post templates (no limit to how many a theme can have)&lt;/li&gt;
&lt;li&gt;Roles and permissions&lt;/li&gt;
&lt;li&gt;And more&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Everything you loved about the old version of Postleaf is still there and then some. And it&#39;s even more simple and beautiful than before.&lt;/p&gt;
&lt;p&gt;You can &lt;a href=&quot;https://github.com/Postleaf/postleaf/releases&quot;&gt;get the source&lt;/a&gt; of the new version on GitHub.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Thoughts on uploads</title>
		<link href="https://www.abeautifulsite.net/posts/thoughts-on-uploads/"/>
		<updated>2017-03-21T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/thoughts-on-uploads/</id>
		<content type="html">&lt;p&gt;Uploads management is a concept I&#39;ve always struggled with in Postleaf, but it&#39;s a necessary evil. Users have to be able to view and delete files they upload; but at the same time, I&#39;ve never felt that it should be an integral part of the app.&lt;/p&gt;
&lt;p&gt;Last night I had to face the fact that Postleaf isn&#39;t going to ship until it has a damn good uploads manager.&lt;/p&gt;
&lt;p&gt;It was time to face the inevitable. I stayed up &lt;a href=&quot;https://twitter.com/postleafapp/status/844069264621559808&quot;&gt;all night&lt;/a&gt; on a sort of &lt;a href=&quot;https://www.youtube.com/watch?v=FbccrO8qKog&quot;&gt;vision quest&lt;/a&gt; for ideas, and ultimately came up with what I feel is the perfect solution for Postleaf.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/uploads-manager.jpg&quot; alt=&quot;A hand drawn wireframe of an uploads manager prototype&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The concept involves a panel that slides up from the bottom of the screen when the control is activated. Images and other files are displayed in lightbox-style gallery, along with the ability to search, delete, and download files. The panel can be dismissed by clicking or tapping outside of it or by pressing the escape key.&lt;/p&gt;
&lt;p&gt;I created this concept because I don&#39;t believe the uploads manager deserves its own dedicated section in the admin panel. People use Postleaf to manage content, not files, so let&#39;s stay focused on what we came here to do.&lt;/p&gt;
&lt;p&gt;Managing files is a secondary task, and this panel approach suits it well. The uploads manager can be accessed from anywhere in the app by pressing &lt;kbd&gt;CMD&lt;/kbd&gt; + &lt;kbd&gt;SHIFT&lt;/kbd&gt; + &lt;kbd&gt;U&lt;/kbd&gt;. Alternatively, it can be activated by a form control and used as a file picker.&lt;/p&gt;
&lt;p&gt;Here&#39;s a glimpse of an early prototype:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/uploads-manager-preview.png&quot; alt=&quot;Screenshot of the uploads manager in the Postleaf dashboard&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I chose a dark background because it brings more focus to your photos and files. I think it works really well, and I&#39;m excited to bring this concept to life in Postleaf.&lt;/p&gt;
&lt;p&gt;At this rate, I should have the uploads manager ready to roll in a couple days!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Importing plain CSS files with Sass</title>
		<link href="https://www.abeautifulsite.net/posts/importing-plain-css-files-with-sass/"/>
		<updated>2017-02-10T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/importing-plain-css-files-with-sass/</id>
		<content type="html">&lt;p&gt;When I first started using Sass, there was one thing that drove me crazy about it compared to Less. For some reason, including a plain CSS file just wasn&#39;t something the compiler wanted to do:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* Uncaught, unspecified &quot;error&quot; event. (Ignoring local @import of &quot;animate.min.css&quot; as resource is missing.) */&lt;/span&gt;
&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;animate.css&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But, annoyingly, the resource &lt;em&gt;is&lt;/em&gt; there. So why does the compiler report it missing?&lt;/p&gt;
&lt;p&gt;I may never understand the logic behind this design decision, but the solution is to simply omit the &lt;code&gt;.css&lt;/code&gt; extension:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* Imports animate.css */&lt;/span&gt;
&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;animate&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works as of version 3.2. And for those using Less, here&#39;s the equivalent syntax:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* Import CSS file using Less */&lt;/span&gt;
&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;css&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;animate.css&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content>
	</entry>
	
	<entry>
		<title>Determining your app&#39;s base directory in Node.js</title>
		<link href="https://www.abeautifulsite.net/posts/determining-your-apps-base-directory-in-nodejs/"/>
		<updated>2017-02-09T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/determining-your-apps-base-directory-in-nodejs/</id>
		<content type="html">&lt;p&gt;Determining your app&#39;s base dir (or &lt;em&gt;document root&lt;/em&gt; if you&#39;re from a PHP background) isn&#39;t as straight forward as you&#39;d think in Node. Here&#39;s a little trick to get a globally available reference to your app&#39;s root directory.&lt;/p&gt;
&lt;p&gt;Add this somewhere towards the start of your main app file (e.g. &lt;code&gt;app.js&lt;/code&gt;):&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;global&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;__basedir &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; __dirname&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This sets a global variable that will always be equivalent to your app&#39;s base dir. Use it just like any other variable:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; yourModule &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;__basedir &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;/path/to/module.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I know what you&#39;re thinking: oh no a global! 😫&lt;/p&gt;
&lt;p&gt;And I would normally agree, but I think this technique is a fair exception if you&#39;re developing an app. Here&#39;s why:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There &lt;a href=&quot;http://stackoverflow.com/a/18721515/567486&quot;&gt;really isn&#39;t&lt;/a&gt; a consistent way to references the base dir without it.&lt;/li&gt;
&lt;li&gt;It&#39;s a fair requirement to set if you&#39;re worried about reusing modules.&lt;/li&gt;
&lt;li&gt;It&#39;s a lot easier and more stable than using &lt;code&gt;../../../file.js&lt;/code&gt; all the time.&lt;/li&gt;
&lt;li&gt;It shares the same naming convention as &lt;code&gt;__dirname&lt;/code&gt; and &lt;code&gt;__filename&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are, of course, other techniques that may or may not be more appropriate depending on your app. However, in my opinion, this approach is the most elegant.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Hashing Passwords with Node.js and bcrypt</title>
		<link href="https://www.abeautifulsite.net/posts/hashing-passwords-with-nodejs-and-bcrypt/"/>
		<updated>2017-02-08T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/hashing-passwords-with-nodejs-and-bcrypt/</id>
		<content type="html">&lt;p&gt;The &lt;a href=&quot;https://www.npmjs.com/package/bcrypt&quot;&gt;bcrypt library on NPM&lt;/a&gt; makes it really easy to hash and compare passwords in Node. If you&#39;re coming from a PHP background, these are roughly equivalent to &lt;a href=&quot;http://php.net/manual/en/function.password-hash.php&quot;&gt;password_hash()&lt;/a&gt; and &lt;a href=&quot;http://php.net/manual/en/function.password-verify.php&quot;&gt;password_verify()&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Bcrypt is the de facto way to hash and store passwords. For a brief explanation of why we use one-way hashes instead of encryption, check out &lt;a href=&quot;http://stackoverflow.com/a/326706&quot;&gt;this answer&lt;/a&gt; on StackOverflow.&lt;/p&gt;
&lt;h2 id=&quot;installing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/hashing-passwords-with-nodejs-and-bcrypt/#installing&quot;&gt;Installing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To use the library, simply install with NPM:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--save&lt;/span&gt; bcrypt&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then include it like this:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; bcrypt &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;bcrypt&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;creating-and-verifying-a-password-hash&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/hashing-passwords-with-nodejs-and-bcrypt/#creating-and-verifying-a-password-hash&quot;&gt;Creating and verifying a password hash&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Bcrypt supports both sync and async methods. The asynchronous approach is recommended because hashing is CPU intensive, and the synchronous version will block the event loop and prevent your app from handling other requests until it finishes.&lt;/p&gt;
&lt;p&gt;Thus, while the sync version is more convenient, it&#39;s best to stick with async if you&#39;re concerned about performance.&lt;/p&gt;
&lt;h3 id=&quot;asynchronous-version&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/hashing-passwords-with-nodejs-and-bcrypt/#asynchronous-version&quot;&gt;Asynchronous version&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Hashing a password is as simple as this. The second argument is the number of rounds to use when generating a salt.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;bcrypt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;myPassword&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; hash&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Store hash&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To verify the password later on:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;bcrypt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;compare&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;somePassword&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; hash&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; res&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;res&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;token comment&quot;&gt;// Passwords match&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;token comment&quot;&gt;// Passwords don&#39;t match&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;synchronous-version&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/hashing-passwords-with-nodejs-and-bcrypt/#synchronous-version&quot;&gt;Synchronous version&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you prefer a synchronous approach, you can do this instead:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; hash &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; bcrypt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hashSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;myPassword&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Store hash&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To verify the password later on:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bcrypt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;compareSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;somePassword&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; hash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token comment&quot;&gt;// Passwords match&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token comment&quot;&gt;// Passwords don&#39;t match&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&#39;s it! You&#39;ve just hashed and verified your first password using Node.js and bcrypt!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Using an ORM</title>
		<link href="https://www.abeautifulsite.net/posts/using-an-orm/"/>
		<updated>2017-02-06T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/using-an-orm/</id>
		<content type="html">&lt;p&gt;I&#39;ve never really bothered with &lt;a href=&quot;https://en.wikipedia.org/wiki/Object-relational_mapping&quot;&gt;ORMs&lt;/a&gt; before, as feelings for them tend to be mixed. I&#39;ve heard that you can spend twice as long learning an ORM as you can coding raw SQL. 🤷🏻‍♂️&lt;/p&gt;
&lt;p&gt;I figured it was time to see for myself. For the Postleaf rebuild, I decided to try out &lt;a href=&quot;http://docs.sequelizejs.com/en/v3/&quot;&gt;Sequelize&lt;/a&gt;. I discovered it some time ago and really liked what I saw, but never had a chance to use it. I&#39;m glad I finally did.&lt;/p&gt;
&lt;p&gt;The previous version of Postleaf required MySQL. All the models were written from scratch, including CRUD methods (create, read, update, delete) and validation. Believe me when I say that you can waste &lt;em&gt;a lot of time&lt;/em&gt; writing your own CRUD methods.&lt;/p&gt;
&lt;p&gt;To make matters worse, some of the queries were proprietary, meaning they&#39;d only work with MySQL. I&#39;ve wanted to remove that requirement for a long time.&lt;/p&gt;
&lt;p&gt;An ORM can alleviate these pain points. Sequelize, for example, lets you define models and validation using a simple JSON object. It even creates the database schema and models for you, after which you can query the database without writing any SQL at all.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Find the user named Joe&lt;/span&gt;
User&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findOne&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Joe&#39;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &quot;Joe&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&#39;s roughly the same as this:&lt;/p&gt;
&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; email &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; users &lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Joe&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It may seem a bit more verbose for simple queries, but once you start associating models the benefits are more easily understood. With just one additional line of code, I can fetch the user along with all of his posts:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Find Joe and fetch all of his posts&lt;/span&gt;
User&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findOne&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Joe&#39;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Post
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &quot;Joe&quot;&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;posts&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Posts authored by Joe&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It gets even more exciting when you realize that Sequelize doesn&#39;t just return the raw data, it returns the data as a series of model objects. That means you can do things like this:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Find Joe and change his name to Bob&lt;/span&gt;
User&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findOne&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Joe&#39;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Bob&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// commit to database&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since raw SQL queries are abstracted into code, I don&#39;t have to worry about database-specific quirks — Sequelize does all that in the background. As long as I stick to their API (and avoid database-specific features), Postleaf will be able to run on top of any database that Sequelize supports. (Currently SQLite, MySQL, MariaDB, MSSQL, and PostgreSQL.)&lt;/p&gt;
&lt;p&gt;For now, I&#39;ve decided to develop with SQLite. It&#39;s fast, and I love having a single database file in a known location that you can quickly duplicate or replace. It&#39;s great for testing, but I&#39;m definitely trying to support all five platforms for release!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Solving the search problem</title>
		<link href="https://www.abeautifulsite.net/posts/solving-the-search-problem/"/>
		<updated>2017-02-06T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/solving-the-search-problem/</id>
		<content type="html">&lt;p&gt;I recently wrote about &lt;a href=&quot;https://www.abeautifulsite.net/posts/using-an-orm&quot;&gt;using an ORM&lt;/a&gt; and how it allowed me to support five different database platforms with minimal effort. There is, however, one feature that even Sequelize couldn&#39;t tackle for me: &lt;em&gt;full-text search&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A full-text search is typically a database feature that lets you locate content just like you would in a search engine. Ideally, the results are ranked by some sort of relevancy score.&lt;/p&gt;
&lt;p&gt;The problem is that not all databases support full-text search out of the box, and the ones that do don&#39;t necessarily rank results the same way.&lt;/p&gt;
&lt;h2 id=&quot;searching-with-sqlite&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/solving-the-search-problem/#searching-with-sqlite&quot;&gt;Searching with SQLite&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I&#39;m using SQLite at the moment for development, and while it supports full-text search, you have to use one of three possible extensions (FTS3, FTS4, FTS5) that must be compiled along with SQLite.&lt;/p&gt;
&lt;p&gt;Having three extensions is confusing enough, much less making users compile their own version of SQLite just to run Postleaf. And none of this accounts for the four other database dialects that I&#39;d like to support.&lt;/p&gt;
&lt;h2 id=&quot;searching-with-mysql&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/solving-the-search-problem/#searching-with-mysql&quot;&gt;Searching with MySQL&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The previous version of Postleaf ran on top of MySQL, which has a built-in full-text search. Once you create an index, you can search against content with relative ease. Results are reasonably relevant, but not amazing.&lt;/p&gt;
&lt;p&gt;Some quirks — it ignores any term that&#39;s three letters or less. So a search for &amp;quot;cat&amp;quot; will always yield zero results. And if you want to rank a post&#39;s title higher than its content (a weighted search), you have to do the math and write the raw SQL yourself. Lame.&lt;/p&gt;
&lt;h2 id=&quot;solving-search-is-hard!&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/solving-the-search-problem/#solving-search-is-hard!&quot;&gt;Solving Search is hard!&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It&#39;s true, search is hard, but this problem is much bigger than Postleaf. Ghost has a &lt;a href=&quot;https://github.com/TryGhost/Ghost/issues/5321&quot;&gt;two year old issue&lt;/a&gt; about it and a lot of people complain that WordPress searches &lt;a href=&quot;http://www.noupe.com/wordpress/improving-the-default-search-experience-in-wordpress-75862.html&quot;&gt;lack relevance&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Sure, if you focus on one particular database or avoid full-text altogether, you can achieve a search that will yield somewhat usable results. It will work, but it won&#39;t be amazing. I think that&#39;s because databases really weren&#39;t meant to do this type of thing.&lt;/p&gt;
&lt;p&gt;A more effective way to solve this problem is with a dedicated search engine such as &lt;a href=&quot;https://www.elastic.co/products/elasticsearch&quot;&gt;Elasticsearch&lt;/a&gt;. Elasticsearch delivers fast, relevant results which is just what we&#39;re looking for! Except, of course, it&#39;s written in Java and can be somewhat difficult to setup.&lt;/p&gt;
&lt;p&gt;Making a complex third-party app a dependency of Postleaf was simply not going to happen. And while there are other options out there, they tend to be more complicated than they&#39;re worth for the simple search that I needed for Postleaf.&lt;/p&gt;
&lt;h2 id=&quot;experimenting-with-lunr&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/solving-the-search-problem/#experimenting-with-lunr&quot;&gt;Experimenting with Lunr&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After some searching around, I began experimenting with a JavaScript library called &lt;a href=&quot;http://lunrjs.com/&quot;&gt;Lunr&lt;/a&gt;. Lunr can be used with Node.js apps or directly in the browser.&lt;/p&gt;
&lt;p&gt;Essentially, you define an index with the fields you want to search. You can weight a field using the boost option:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; index &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lunr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;title&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;boost&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;content&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;id&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then you add items to the index:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;index&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Lorem Ipsum&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Lorem ipsum dolor...&#39;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then you can search quite easily:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;index&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;lorem ipsum&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Lunr is fast, lightweight, and JavaScript. And it&#39;s results are spot on! I immediately knew it would be a key component to my full-text search solution, but some challenges still remained.&lt;/p&gt;
&lt;h2 id=&quot;implementing-lunr-in-postleaf&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/solving-the-search-problem/#implementing-lunr-in-postleaf&quot;&gt;Implementing Lunr in Postleaf&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;My initial approach to implementing Lunr turned out to be expensive. I wanted to see how fast fetching, indexing, and searching would be on the fly. It looked something like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Fetch id, title, and content of all posts when a request comes in.&lt;/li&gt;
&lt;li&gt;Create a Lunr index.&lt;/li&gt;
&lt;li&gt;Add each post to the index.&lt;/li&gt;
&lt;li&gt;Search the index for the user&#39;s query.&lt;/li&gt;
&lt;li&gt;eturn all posts that matched the IDs that Lunr had returned.&lt;/li&gt;
&lt;li&gt;DesTroy the Lunr index.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This happened on every single request requiring a search. Obviously it wasn&#39;t ideal, but I was surprised at how well it performed even for 1,000 posts. At some point after that, the delay became somewhat noticeable (I think it was 2-3 seconds or so per query).&lt;/p&gt;
&lt;p&gt;I ended up optimizing my approach so the search index is only built once when the app starts. The index persists in memory and, using &lt;a href=&quot;http://docs.sequelizejs.com/en/latest/docs/hooks/&quot;&gt;Sequelize hooks&lt;/a&gt;, it stays up to date when you add, update, or delete posts.&lt;/p&gt;
&lt;p&gt;Since the search happens 100% in memory, it&#39;s incredibly fast.&lt;/p&gt;
&lt;p&gt;The biggest drawback to this approach is, of course, keeping the search index in memory. However, for 10,000 posts I extrapolated a footprint of just under 30MB. If you have that many posts, I hope your VPS is strong enough to handle it. 😆&lt;/p&gt;
&lt;p&gt;Needless to say, the Postleaf rebuild is shipping with a fast, relevant, database-agnostic full-text search thanks to Lunr and a very clever Node.js implementation.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Moving to Node.js</title>
		<link href="https://www.abeautifulsite.net/posts/moving-to-nodejs/"/>
		<updated>2017-02-06T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/moving-to-nodejs/</id>
		<content type="html">&lt;p&gt;The first version of Postleaf was written in PHP and lives on as Leafpub. It&#39;s a beautiful piece of software that I&#39;m very proud of, but I decided to move the project to Node.js for a few important reasons. This is by no means a knock on PHP, which will always have a special place in my heart, but more of a changing with the times realization.&lt;/p&gt;
&lt;p&gt;If you&#39;ve ever worked with Node.js before, you&#39;ll know that it&#39;s fast. &lt;em&gt;Very fast.&lt;/em&gt; The beauty of Node is that it&#39;s minimal by design. It can do anything you want it to do with the right packages, and this concept aligns very closely with my vision for Postleaf.&lt;/p&gt;
&lt;p&gt;You&#39;ve probably been hearing &lt;em&gt;JavaScript is the Future&lt;/em&gt; a lot lately. I think there&#39;s a lot of truth to that statement, especially as platforms such as &lt;a href=&quot;https://www.electronjs.org/&quot;&gt;Electron&lt;/a&gt; and &lt;a href=&quot;https://phonegap.com/&quot;&gt;PhoneGap&lt;/a&gt; gain popularity and bring JavaScript to places it&#39;s never been before.&lt;/p&gt;
&lt;p&gt;In general, I don&#39;t think it makes a lot of sense to write the same app three different times in three different languages for three different platforms (think iOS, Android, and Windows Phone apps, for example). We&#39;ve been doing it for years, but I foresee JavaScript playing a vital role in closing that gap.&lt;/p&gt;
&lt;p&gt;By moving Postleaf to Node.js, its foundation is becoming much more nimble, making it easier to pivot and adapt to an ever-changing technology ecosystem. That, unfortunately, is something I don&#39;t think PHP will be able to do.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>SSH failing on macOS Sierra</title>
		<link href="https://www.abeautifulsite.net/posts/ssh-failing-on-macos-sierra/"/>
		<updated>2017-01-15T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/ssh-failing-on-macos-sierra/</id>
		<content type="html">&lt;p&gt;For me, upgrading to MacOS Sierra broke a lot of things that use SSH, including Transmit, Sequel Pro, and a handful of other apps. In fact, it seems to break any app that uses an SSH key with a passphrase. 🤔&lt;/p&gt;
&lt;p&gt;The solution I found was to tell SSH to use the MacOS keychain. Simply edit &lt;code&gt;~/.ssh/config&lt;/code&gt; and add the following (you can safely create the file if it doesn&#39;t exist):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Host *
    UseKeychain yes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&#39;s it! I didn&#39;t even have to restart SSH and everything is connecting fine again. 💪&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Getting it right</title>
		<link href="https://www.abeautifulsite.net/posts/getting-it-right/"/>
		<updated>2017-01-14T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/getting-it-right/</id>
		<content type="html">&lt;p&gt;To my awesome users:&lt;/p&gt;
&lt;p&gt;I&#39;ve been taking some time to reimagine what Postleaf should have been. Yes, the betas were pretty awesome, but they weren&#39;t what I wanted them to be in terms of design, code, and function. I can do better, and you deserve nothing less than my very best.&lt;/p&gt;
&lt;p&gt;The last few months were difficult for me as I struggled to find my place in the world of content management. I thought about giving it up and getting out of software altogether. My vision was cloudy, my passion had faded. Recently, I looked at Postleaf from a completely different perspective and everything started to make sense again.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I have a vision to bring simple, beautiful publishing to the world. And I&#39;m not going to stop until I get it right.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Thanks for giving me the time I needed to find myself.&lt;/p&gt;
&lt;p&gt;Postleaf will be back very soon. And it will be better than you ever imagined.&lt;/p&gt;
&lt;p&gt;— Cory&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>SimpleImage 3.0</title>
		<link href="https://www.abeautifulsite.net/posts/simpleimage-3/"/>
		<updated>2017-01-10T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/simpleimage-3/</id>
		<content type="html">&lt;p&gt;&lt;a href=&quot;https://www.abeautifulsite.net/posts/the-simple-image-library-for-php&quot;&gt;Back in 2011&lt;/a&gt;, I released the first version of SimpleImage for PHP — an open source project for working with images.&lt;/p&gt;
&lt;p&gt;Today, version 3.0 has landed, and there&#39;s a lot to love about it.&lt;/p&gt;
&lt;h2 id=&quot;overview&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/simpleimage-3/#overview&quot;&gt;Overview&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here&#39;s how it works at a glance:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token comment&quot;&gt;// Create a new SimpleImage object&lt;/span&gt;
 &lt;span class=&quot;token variable&quot;&gt;$image&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name class-name-fully-qualified&quot;&gt;claviska&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;SimpleImage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

 &lt;span class=&quot;token comment&quot;&gt;// Magic! ✨&lt;/span&gt;
 &lt;span class=&quot;token variable&quot;&gt;$image&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fromFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;image.jpg&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// load image.png&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;autoOrient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// adjust orientation based on exif data&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;resize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;320&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// resize to 320x200 pixels&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;flip&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;x&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// flip horizontally&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;colorize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;DarkBlue&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// tint dark blue&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;black&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// add a 10 pixel black border&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;overlay&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;watermark.png&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;bottom right&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// add a watermark image&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;new-image.png&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;image/png&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// convert to PNG and save a copy to new-image.png&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toScreen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// output to the screen&lt;/span&gt;

 &lt;span class=&quot;token comment&quot;&gt;// And much more! 💪&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$err&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token comment&quot;&gt;// Handle errors&lt;/span&gt;
 &lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$err&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;requirements&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/simpleimage-3/#requirements&quot;&gt;Requirements&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;PHP 5.6+&lt;/li&gt;
&lt;li&gt;GD extension&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;features&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/simpleimage-3/#features&quot;&gt;Features&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Supports reading, writing, and converting GIF, JPEG, PNG, WEBP formats.&lt;/li&gt;
&lt;li&gt;Reads and writes files and data URIs.&lt;/li&gt;
&lt;li&gt;Manipulation: crop, resize, overlay/watermark, adding TTF text&lt;/li&gt;
&lt;li&gt;Drawing: arc, border, dot, ellipse, line, polygon, rectangle, rounded rectangle&lt;/li&gt;
&lt;li&gt;Filters: blur, brighten, colorize, contrast, darken, desaturate, edge detect, emboss, invert, pixelate, sepia, sketch&lt;/li&gt;
&lt;li&gt;Utility methods: color adjustment, darken/lighten color, exif data, height/width, mime type, orientation&lt;/li&gt;
&lt;li&gt;Color arguments can be passed in as any CSS color (e.g. `LightBlue`), a hex color, or an RGB(A) array.&lt;/li&gt;
&lt;li&gt;Support for alpha-transparency (GIF, PNG, WEBP)&lt;/li&gt;
&lt;li&gt;Chainable methods&lt;/li&gt;
&lt;li&gt;Uses exceptions&lt;/li&gt;
&lt;li&gt;Load with Composer or manually (just one file)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/claviska/SimpleImage#differences-from-simpleimage-2x&quot;&gt;The readme&lt;/a&gt; has a list of changes from the 2.x version of SimpleImage.&lt;/p&gt;
&lt;h2 id=&quot;download&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/simpleimage-3/#download&quot;&gt;Download&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/claviska/SimpleImage&quot;&gt;Download the latest version on GitHub.&lt;/a&gt;&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Don&#39;t hate on PHP</title>
		<link href="https://www.abeautifulsite.net/posts/dont-hate-on-php/"/>
		<updated>2016-11-22T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/dont-hate-on-php/</id>
		<content type="html">&lt;p&gt;It wasn&#39;t long after launching a major open source PHP project until I started hearing things like &lt;a href=&quot;https://news.ycombinator.com/item?id=12183268&quot;&gt;this&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I [...] immediately drop interest in a project when I see that it is implemented in PHP.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A lot of people have been &lt;a href=&quot;https://www.reddit.com/r/programming/comments/2c9i9v/why_does_php_suck/&quot;&gt;hating&lt;/a&gt; &lt;a href=&quot;https://adambard.com/blog/you-write-php-because-you-dont-know-better/&quot;&gt;on&lt;/a&gt; &lt;a href=&quot;https://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/&quot;&gt;PHP&lt;/a&gt; &lt;a href=&quot;https://evertpot.com/PHP-Sucks/&quot;&gt;in&lt;/a&gt; &lt;a href=&quot;https://whydoesitsuck.com/why-does-php-suck/&quot;&gt;recent&lt;/a&gt; &lt;a href=&quot;https://wiki.theory.org/YourLanguageSucks#PHP_sucks_because&quot;&gt;years&lt;/a&gt;, and frankly, they have every right to. In fact, you can hate on any language you want for whatever reasons you want. I could honestly care less.&lt;/p&gt;
&lt;p&gt;But let me stop you from generalizing that opinion and shoving it down everyone&#39;s throat.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/captain-ssh.gif&quot; alt=&quot;The captain shakes his head &amp;quot;no&amp;quot; and goes &amp;quot;shh&amp;quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Sure, there are plenty of things I would change about PHP if I were the one designing it. I could say the same thing about every single programming language in the world, but that&#39;s not my job. I&#39;m not engineering programming languages, I&#39;m building web applications with them. And I&#39;m certainly not going to undermine the hard working people who &lt;em&gt;are&lt;/em&gt; designing these languages, whether I prefer to use them or not.&lt;/p&gt;
&lt;h2 id=&quot;it&#39;s-just-a-tool&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/dont-hate-on-php/#it&#39;s-just-a-tool&quot;&gt;It&#39;s just a tool&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;What developers seem to forget is that programming languages are nothing more than tools that help you get something done. Just like the tools in your garage, each and every one has a special purpose. Not every tool will work well for every job, and some tools do the same exact thing in very different ways. Variety is the spice of life.&lt;/p&gt;
&lt;p&gt;But nobody tells a roofer his hammer is shit. Nobody tells a plumber his pipe cutter sucks. Nobody tells a carpenter his level is garbage. Each craftsman has their own preference based on their own experience, and that&#39;s perfectly acceptable.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/hammer-oh.gif&quot; alt=&quot;A lady hits the wall with a hammer and acts surprised when a hole appears&quot; /&gt;&lt;/p&gt;
&lt;p&gt;If you don&#39;t like a tool, put it back in the toolbox. It&#39;s that simple. Don&#39;t run around telling everyone how shitty a programming language is because you don&#39;t like it. It might be your opinion, but it&#39;s a subjective, arrogant, and disrespectful opinion. Instead of coming off as a conceited asshole, use your expertise to advise people why a &lt;em&gt;specific tool&lt;/em&gt; might be better for a &lt;em&gt;specific purpose&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Even if you&#39;re right with your reason, it won&#39;t matter if you&#39;re wrong with your approach. We&#39;re supposed to be professionals — what say we start acting like it? Who knows what tomorrow will bring. For now, let&#39;s stop fussing over the tools we&#39;re using and focus on the goals we&#39;re trying to accomplish.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Thoughts on comments</title>
		<link href="https://www.abeautifulsite.net/posts/thoughts-on-comments/"/>
		<updated>2016-06-12T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/thoughts-on-comments/</id>
		<content type="html">&lt;p&gt;For as long as I can remember, comments have been a staple of blogging software. After all, what&#39;s a good blog post without a relevant discussion to accompany it?&lt;/p&gt;
&lt;p&gt;You might find it strange to learn that Postleaf doesn&#39;t ship with comments. This is by design, and I&#39;ll explain why in this post.&lt;/p&gt;
&lt;h2 id=&quot;the-comment-problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/thoughts-on-comments/#the-comment-problem&quot;&gt;The Comment Problem&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Everyone thinks they want comments on their blog. That is, until they have to deal with the problems that those comments create. The biggest problem is by far comment spam. This is such a huge issue that the makers of WordPress established &lt;a href=&quot;https://akismet.com/&quot;&gt;a dedicated service&lt;/a&gt; just to fight it.&lt;/p&gt;
&lt;p&gt;But why does it happen? Well, spammers post bogus comments, those comments contain links, and those links make them money when people click. Since it costs them practically nothing to do it, they keep posting comment spam. A lot of it.&lt;/p&gt;
&lt;h2 id=&quot;fighting-spam&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/thoughts-on-comments/#fighting-spam&quot;&gt;Fighting Spam&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are many ways to fight comment spam. One is to moderate all comments before they go public. This really sucks because comments don&#39;t go live immediately and you have to manually approve every single one. That makes it hard to have a discussion and it can fill up your inbox.&lt;/p&gt;
&lt;p&gt;Another approach is to add some kind of crazy &lt;a href=&quot;https://en.wikipedia.org/wiki/CAPTCHA&quot;&gt;CAPTCHA&lt;/a&gt; test to your comment form, but these can be difficult even for humans and often discourage visitors from leaving comments.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://xkcd.com/233/&quot;&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/a-new-captcha-approach.png&quot; alt=&quot;XKCD comic: a new CAPTCHA approach&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Perhaps the most effective approach is to require users to create an account, verify their email address, and then let them post. But let&#39;s be honest, how many people are actually going to take the time to do that? In my experience, not very many. Most people aren&#39;t comfortable typing their email address into a web form, so they&#39;re probably not going to give you their name, email address, and a password.&lt;/p&gt;
&lt;h2 id=&quot;everyone-has-an-opinion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/thoughts-on-comments/#everyone-has-an-opinion&quot;&gt;Everyone Has An Opinion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Yes, everyone. And many of them feel invincible hiding behind their keyboard so they&#39;re not afraid to force that opinion down your throat in the comments. Which brings us to the next big problem with comments: &lt;em&gt;accountability&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Even if you force users to create an account before posting a comment, there&#39;s nothing stopping them from using a bogus name and email address. You&#39;re going to end up with a lot of flaming, trash talking, and senseless discussions because there&#39;s a huge lack of accountability on the Internet.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://xkcd.com/386/&quot;&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/duty-calls.png&quot; alt=&quot;XKCD comic: duty calls&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So how do we fix that? Well, I could spend the next year trying to develop the perfect comment system for Postleaf, but it&#39;s a massive undertaking and, to be honest, it would probably never really be good enough.&lt;a href=&quot;https://xkcd.com/233/&quot;&gt;https://xkcd.com/233/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So what now? Do we ditch comments altogether? 🤔&lt;/p&gt;
&lt;h2 id=&quot;a-better-way&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/thoughts-on-comments/#a-better-way&quot;&gt;A Better Way&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Some time ago, I got tired of dealing with comment problems and disabled them on my blog. The conversation went quiet, and I started to feel alone in the world. (Ok, not really, but still, not allowing comments at all was pretty lame.)&lt;/p&gt;
&lt;p&gt;Eventually, I decided to try out &lt;a href=&quot;https://disqus.com/&quot;&gt;Disqus&lt;/a&gt;. I added a small JavaScript snippet to my website and BOOM, comments. But not just any comments, good comments.&lt;/p&gt;
&lt;h3 id=&quot;why-disqus-works&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/thoughts-on-comments/#why-disqus-works&quot;&gt;Why Disqus Works&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The power of Disqus is in its community. Users login to their Disqus account (which they can create from your site if they don&#39;t already have one) and they&#39;re able to post comments to your blog.&lt;/p&gt;
&lt;p&gt;You&#39;re probably wondering, &amp;quot;how is this any different from letting them create an account on &lt;em&gt;my&lt;/em&gt; website?&amp;quot;&lt;/p&gt;
&lt;p&gt;It&#39;s very different, because they only need to create one account which can be used on any website that runs Disqus. You have immediate access to millions of registered users that you don&#39;t have to bother keeping track of. Furthermore, Disqus lets users login through Facebook, Twitter, or Google, which provides the best form of accountability you&#39;re going to get on the Internet.&lt;/p&gt;
&lt;p&gt;Since I started using Disqus, I haven&#39;t had to deal with comment spam and the conversation has been just that — a conversation. Disqus handles notifications so I know when people post comments and they know when I respond. I can even reply to notifications with various commands to moderate comments by email — a huge time saver! 📫&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Update: February 26, 2017&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As of February 2017, Disqus converted their free plan into an ad-supported plan. That means, unless you remove Disqus from your website or fork up $10 per month, your website is going to show ads.&lt;/p&gt;
&lt;p&gt;I&#39;m in no way opposed to a SaaS making money, but this feels like a bait and switch. Nobody gets to opt out. Nobody gets grandfathered in. You either pay up, stop using Disqus, or your visitors get subjected to whatever ads Disqus wants to show on your website.&lt;/p&gt;
&lt;p&gt;Not having control over one&#39;s own website is something I&#39;m vehemently against.&lt;/p&gt;
&lt;h2 id=&quot;comments-in-postleaf&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/thoughts-on-comments/#comments-in-postleaf&quot;&gt;Comments in Postleaf&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Comments shouldn&#39;t be a chore. They should form relevant, civil discussions that engage your visitors. When you spend all your time moderating comments, you end up with less time for the finer things in life.&lt;/p&gt;
&lt;p&gt;That&#39;s why I intentionally left comments out of the Postleaf core. If you want them, I suggest finding a third-party platform or service that suits your needs for now. They are absolutely the best way to promote relevant discussions on your blog without the hassle of dealing with traditional comments.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Code can change</title>
		<link href="https://www.abeautifulsite.net/posts/code-can-change/"/>
		<updated>2016-05-10T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/code-can-change/</id>
		<content type="html">&lt;p&gt;As a web developer, your code is often visible to anyone who wants to review it. If you&#39;re like me, you might get stressed out about the thought of people looking at your work and critiquing or criticizing your app&#39;s design.&lt;/p&gt;
&lt;p&gt;Take a deep breath, recenter, and remember that code can always change. That&#39;s why we have version numbers!&lt;/p&gt;
&lt;p&gt;Even the most seasoned developers have their own opinion of what &amp;quot;good design&amp;quot; is. No matter how long you spend engineering or reworking your app&#39;s design, there&#39;s always, always, always going to be more ways to improve it. In fact, the code you write today will probably look like crap to you a year from now. That&#39;s part of the learning process.&lt;/p&gt;
&lt;p&gt;Remember, code is dynamic. It&#39;s meant to change. So don&#39;t obsess about making it perfect. Just make it work, make it easy to understand, and realize you&#39;ll probably be changing it one day.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>A better way to write config files in PHP</title>
		<link href="https://www.abeautifulsite.net/posts/a-better-way-to-write-config-files-in-php/"/>
		<updated>2016-05-02T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/a-better-way-to-write-config-files-in-php/</id>
		<content type="html">&lt;p&gt;How many times have you seen something like this in a config file?&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$db_host&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;localhost&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;$db_name&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;somedb&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;$db_user&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;someuser&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;$db_pass&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;somepass&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, of course, it gets included and the variables are referenced as globals:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;config.php&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$db_host&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &#39;localhost&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;a-better-way&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/a-better-way-to-write-config-files-in-php/#a-better-way&quot;&gt;A better way&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I&#39;m not a fan of using global variables when they can be avoided, so here&#39;s an alternative that gives you much more flexibility with your config files.&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;host&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;localhost&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;name&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;somedb&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;user&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;someuser&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;pass&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;somepass&#39;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Simply returning the array allows you to include it into any variable you choose, which is much nicer than cluttering the global namespace with your config.&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$database&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;config.php&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$database&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;host&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &#39;localhost&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, you can return any data you want with this approach — even a multidimensional array.&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;database&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;host&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;localhost&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;name&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;somedb&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;user&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;someuser&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;pass&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;somepass&#39;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;other-stuff&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is by far my favorite way to write config files in PHP.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>How to upgrade or downgrade Node.js using npm</title>
		<link href="https://www.abeautifulsite.net/posts/how-to-upgrade-or-downgrade-nodejs-using-npm/"/>
		<updated>2016-04-05T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/how-to-upgrade-or-downgrade-nodejs-using-npm/</id>
		<content type="html">&lt;p&gt;Need to update your version of &lt;a href=&quot;https://nodejs.org/&quot;&gt;Node.js&lt;/a&gt;? Here&#39;s how you can upgrade or downgrade from the command line using npm.&lt;/p&gt;
&lt;h2 id=&quot;upgrading-to-the-latest-stable-version&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/how-to-upgrade-or-downgrade-nodejs-using-npm/#upgrading-to-the-latest-stable-version&quot;&gt;Upgrading to the latest stable version&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This will update you to the latest available stable version:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; cache clean &lt;span class=&quot;token parameter variable&quot;&gt;-f&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-g&lt;/span&gt; n
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; n stable&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;upgrading-to-the-latest-lts-version&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/how-to-upgrade-or-downgrade-nodejs-using-npm/#upgrading-to-the-latest-lts-version&quot;&gt;Upgrading to the latest LTS version&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Node also offers a &lt;a href=&quot;https://github.com/nodejs/LTS/&quot;&gt;long-term support (LTS) version&lt;/a&gt;. If you need that version (or any other), simply specify the version number you want:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; cache clean &lt;span class=&quot;token parameter variable&quot;&gt;-f&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-g&lt;/span&gt; n
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; n &lt;span class=&quot;token number&quot;&gt;4.4&lt;/span&gt;.2&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;checking-your-node-version&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/how-to-upgrade-or-downgrade-nodejs-using-npm/#checking-your-node-version&quot;&gt;Checking your Node version&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To see which version of Node is currently installed, simply run:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-v&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The version number displayed is the one that&#39;s currently active on your machine.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Adding and removing virtual hosts on Ubuntu 14.04</title>
		<link href="https://www.abeautifulsite.net/posts/adding-and-removing-virtual-hosts-on-ubuntu-1404/"/>
		<updated>2016-03-29T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/adding-and-removing-virtual-hosts-on-ubuntu-1404/</id>
		<content type="html">&lt;p&gt;Here&#39;s a cheat sheet for working with virtual hosts on an Ubuntu server. The instructions assume you&#39;re not logged in as the root user. Change &lt;em&gt;&lt;a href=&quot;http://example.com/&quot;&gt;example.com&lt;/a&gt;&lt;/em&gt; to your own domain/subdomain.&lt;/p&gt;
&lt;h2 id=&quot;adding-a-virtual-host&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/adding-and-removing-virtual-hosts-on-ubuntu-1404/#adding-a-virtual-host&quot;&gt;Adding a virtual host&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Create the directory for your new site and grant permissions. If your user isn&#39;t part of the &lt;code&gt;www-data&lt;/code&gt; group, you might want to adjust the second line:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; /var/www/example.com/public&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;_html
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;chown&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-R&lt;/span&gt; &lt;span class=&quot;token environment constant&quot;&gt;$USER&lt;/span&gt;:www-data /var/www/example.com/public&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;_html
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;chmod&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-R&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;755&lt;/span&gt; /var/www/example.com&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add an index page (optional):&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;vim&lt;/span&gt; /var/www/example.com/public&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;_html/index.php&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create the virtual host config file:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;vim&lt;/span&gt; /etc/apache2/sites-available/example.com.conf&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&#39;s a very basic example config file you can start with. Paste it in and adjust as necessary:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;VirtualHost *:80&amp;gt;
  ServerAdmin admin@example.com
  ServerName example.com
  ServerAlias www.example.com

  DocumentRoot /var/www/example.com/public&#92;_html
  &amp;lt;Directory /var/www/example.com/public&#92;_html&amp;gt;
    Options -Indexes
    AllowOverride All
    Order Allow,Deny
    Allow from All
  &amp;lt;/Directory&amp;gt;

  ErrorLog ${APACHE&#92;_LOG&#92;_DIR}/error.log
  CustomLog ${APACHE&#92;_LOG&#92;_DIR}/access.log combined
&amp;lt;/VirtualHost&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now enable the new virtual host and restart Apache:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; a2ensite example.com.conf
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;service&lt;/span&gt; apache2 restart&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If your DNS is already configured, your site should be available at &lt;em&gt;&lt;a href=&quot;http://example.com/&quot;&gt;example.com&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;removing-a-virtual-host&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/adding-and-removing-virtual-hosts-on-ubuntu-1404/#removing-a-virtual-host&quot;&gt;Removing a virtual host&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;First, disable the virtual host and restart Apache:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; /etc/apache2/sites-available-example.com.conf
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-Rf&lt;/span&gt; /var/www/example.com&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point, the site is disabled and will no longer be accessible.&lt;/p&gt;
&lt;p&gt;Now just remove the config file and cleanup the &lt;code&gt;/var/www/&lt;/code&gt; directory to permanently remove the site and all of its files:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; /etc/apache2/sites-available/example.com.conf
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-Rf&lt;/span&gt; /var/www/example.com&lt;/code&gt;&lt;/pre&gt;
</content>
	</entry>
	
	<entry>
		<title>Lessons from a failed Kickstarter</title>
		<link href="https://www.abeautifulsite.net/posts/lessons-from-a-failed-kickstarter/"/>
		<updated>2016-03-28T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/lessons-from-a-failed-kickstarter/</id>
		<content type="html">&lt;p&gt;Last week, I launched Particle on Kickstarter. Today, I pulled the plug and canceled the campaign. We had 50 backers and were 5% funded. So why would I do this with 25 days left to go?&lt;/p&gt;
&lt;p&gt;The fact is, this campaign failed before it started, and it was all my fault. I became so consumed by building and running the Kickstarter that I lost my focus on the product I was creating. Here are some of the things I did wrong and why I terminated the campaign early.&lt;/p&gt;
&lt;h2 id=&quot;not-building-a-following&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/lessons-from-a-failed-kickstarter/#not-building-a-following&quot;&gt;Not building a following&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The most important element to a successful crowdfunding campaign is reaching people. Not just anyone, but people interested in what you have to offer — potential backers. Before launching on Kickstarter, I was well aware that many campaigns spent months or even years building a following prior to launching.&lt;/p&gt;
&lt;p&gt;This was my fatal mistake. I thought I could bypass this requirement because I had a network of online properties geared towards web designers and developers (to the tune of 200,000 visitors a month). I went all in hoping to cross promote Particle to people who didn&#39;t know what the hell it was and people who weren&#39;t even looking for it.&lt;/p&gt;
&lt;p&gt;The results of this obviously weren&#39;t favorable. In hindsight, I would have been better off buying ad space on the back of milk cartons. Or maybe not...&lt;/p&gt;
&lt;h2 id=&quot;relying-on-advertisements&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/lessons-from-a-failed-kickstarter/#relying-on-advertisements&quot;&gt;Relying on advertisements&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As a SaaS owner, I&#39;m no stranger to buying banner ads to promote my services. When I realized my first plan of action wasn&#39;t performing very well, I figured I&#39;d try a paid advertisement. I knew this was a bad idea, but surely people would see how great my unreleased Kickstarter product was in a 300x125 banner ad and start throwing dollar bills at it!&lt;/p&gt;
&lt;p&gt;Yeah, what was I thinking? It only took a couple days to confirm this mistake. Even with a million impressions that ad wouldn&#39;t have come close to paying for itself — and this was a highly targeted website too. Fortunately, I was able to switch it to point to my other service so it wasn&#39;t a complete waste of money.&lt;/p&gt;
&lt;p&gt;In short, if you rely on ads to drive traffic to your crowdfunding campaign, you&#39;re gonna have a bad time.&lt;/p&gt;
&lt;h2 id=&quot;falling-for-kickstarter-spam&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/lessons-from-a-failed-kickstarter/#falling-for-kickstarter-spam&quot;&gt;Falling for kickstarter spam&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Something I didn&#39;t realize until after my campaign launched is that you&#39;ll receive a ton of spam through Kickstarter&#39;s messaging system. You&#39;ll get messages from people who seem legit, but obviously aren&#39;t when you look closely at their profile (hint: a signup date of today is a dead giveaway).&lt;/p&gt;
&lt;p&gt;People will offer to write and submit press releases for you, &amp;quot;enhance your SEO,&amp;quot; send out &amp;quot;social media blasts,&amp;quot; and more. They&#39;ll promise to boost your campaign&#39;s numbers and they&#39;ll boast about how successful their services have been with similar crowdfunding campaigns. One clever spammer even took the time to locate my email address and message me outside of Kickstarter&#39;s system. Nice try, dude!&lt;/p&gt;
&lt;p&gt;These offers may seem tempting, but most of them are scams — some more obvious than others. I only fell for one called BackerClub, which costs $379, but you only pay if you receive $379 or more from backers in their network. Sounds too good to be true, right? It is. Here&#39;s how they scam you.&lt;/p&gt;
&lt;p&gt;BackerClub pretends to be exclusive. You have to &amp;quot;apply&amp;quot; to be featured in their network. Soon after, you&#39;ll receive an email telling you that you&#39;ve been accepted, but due to some bogus algorithm, they need $79 up front to make it worth their while to feature your campaign. If you&#39;re stupid enough to pay it, they&#39;ll send out a couple emails (probably just to you, who knows) that will drive pretty much zero traffic to your campaign.&lt;/p&gt;
&lt;p&gt;It&#39;s amazing how crowdfunding has spawned an entire ecosystem of scumbags who feed off creators that are trying to raise money for projects they&#39;ve put so much heart and soul into. Trust me, no matter how desperate you are or how good it sounds, it&#39;s bullshit.&lt;/p&gt;
&lt;h2 id=&quot;promoting-via-social-media&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/lessons-from-a-failed-kickstarter/#promoting-via-social-media&quot;&gt;Promoting via social media&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This goes hand in hand with not building a following, but I did have a little bit of success promoting Particle on Twitter. Obviously, your results will be better if you have a strong network established and you maintain proper etiquette.&lt;/p&gt;
&lt;p&gt;The problem with Twitter, however, is that you can&#39;t really reach out to people without spamming them. That&#39;s sort of the nature of their platform, but it&#39;s still freaking spam. Although some backers did originate from Twitter, the whole social media thing went south rather quickly.&lt;/p&gt;
&lt;p&gt;It starts with an innocent post that you pin to your profile. Then you reach out to a few people who follow you but you only sort of know. Then you try to insert yourself into relevant conversations with people you don&#39;t know. Then you use Advanced Search to look for derogatory things about your competitors and feed on peoples&#39; frustrations by trying to save the day with — guess what — a fucking Kickstarter link asking them for money!&lt;/p&gt;
&lt;p&gt;You start crapping out links to your project with every tweet and your whole social media strategy turns into a total shitfest that you&#39;re embarrassed to look at the following day.&lt;/p&gt;
&lt;p&gt;Don&#39;t &amp;quot;promote&amp;quot; your campaign like I did. While I did recruit a handful of backers from Twitter, it wasn&#39;t worth the effort or the dent in my reputation. There&#39;s a right way and a wrong way to promote things on social media. That was the wrong way.&lt;/p&gt;
&lt;h2 id=&quot;hoping-for-a-break&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/lessons-from-a-failed-kickstarter/#hoping-for-a-break&quot;&gt;Hoping for a break&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If your Plan B involves sending emails to everyone at TechCrunch, Mashable, and every other big name blog you can think of hoping to get picked up, don&#39;t fucking launch a crowdfunding campaign.&lt;/p&gt;
&lt;p&gt;I knew this from the start, but I figured I&#39;d try anyway. I spent two days sending out personalized emails inviting journalists, bloggers, or whoever else I thought would be interested in a private, prerelease demo of Particle. Crickets.&lt;/p&gt;
&lt;p&gt;It&#39;s not that they don&#39;t give a shit about Particle, they just have a million emails a day flooding their inbox. You really have to stand out, and even that&#39;s probably not enough if you haven&#39;t actually launched your product yet.&lt;/p&gt;
&lt;p&gt;Honestly, who wants to write about a blogging platform that hasn&#39;t launched yet? Not TechCrunch or Mashable, that&#39;s for sure.&lt;/p&gt;
&lt;h2 id=&quot;not-having-a-shill&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/lessons-from-a-failed-kickstarter/#not-having-a-shill&quot;&gt;Not having a shill&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Crowdfunding is a tough nut to crack if you&#39;re a new creator. It would have helped a lot to have the support of someone reputable openly supporting the project. In Particle&#39;s case, a well-known blogger, for example, could have helped spread the word and instill more confidence in potential backers.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.kickstarter.com/projects/507726696/quantum-chess/description&quot;&gt;Quantum Chess&lt;/a&gt; is a great example. They managed to get Paul Rudd to make a comedic video of him and Stephen Hawking playing the game, and that propelled them to exceed their funding goal by almost $3,000. Really, almost $33,000 for a digital chess game (that I&#39;m also guilty of backing). You need a shill.&lt;/p&gt;
&lt;h2 id=&quot;letting-it-consume-you&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/lessons-from-a-failed-kickstarter/#letting-it-consume-you&quot;&gt;Letting it consume you&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Those are all things I failed gloriously at in terms of promoting the campaign, but that&#39;s not the reason I pulled the plug. Even if Particle wouldn&#39;t have met its funding goal, it would have been fun to see just how much it would have reached.&lt;/p&gt;
&lt;p&gt;By far, what I hated most about running a crowdfunding campaign was how it completely consumed me. I knew it would be a lot of work, and I&#39;m OK with a lot of work, but I wasn&#39;t aware of how it eats your soul, shits it out, and then eats it again.&lt;/p&gt;
&lt;p&gt;I spent a month and a half building Particle&#39;s campaign, obsessing over each and every little detail. I filmed the video twice, then bought a new camera and filmed it at least four more times trying to get it right. I rewrote the script countless times. I added closed captions to both videos. I spent hours looking for the right music, budgeting, planning out rewards, tweaking content, and crafting images to make Particle as sexy as possible on Kickstarter. I did everything except what I actually like to do, and I wasted a lot of time doing it.&lt;/p&gt;
&lt;p&gt;I remember looking at the launch button last Tuesday. After so much preparation, was it finally time? I knew I wasn&#39;t prepared well enough, but I couldn&#39;t afford delaying any longer. Or maybe I just couldn&#39;t stand being away from the code as long as I&#39;d been. Maybe I was just fed up with staring at myself and watching screencasts of Particle for hours on end. That stupid music still plays in my head.&lt;/p&gt;
&lt;p&gt;With an audible &amp;quot;fuck it,&amp;quot; my finger clicked the launch button.&lt;/p&gt;
&lt;p&gt;That&#39;s when I should have realized I made the wrong decision. I didn&#39;t prepare well enough, but I was so ready to be done creating that stupid campaign that I just couldn&#39;t stand it any longer. I just wanted to get it over with.&lt;/p&gt;
&lt;p&gt;Particle launched when it shouldn&#39;t have launched. In fact, it probably never should have been on Kickstarter. I became too consumed by the magic and allure of crowdfunding that I completely lost my ability to think straight. Now, just five days into the live campaign I&#39;m beginning to lose my mind. What has this circus act turned me into? This isn&#39;t me. This isn&#39;t Particle.&lt;/p&gt;
&lt;h2 id=&quot;what&#39;s-next%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/lessons-from-a-failed-kickstarter/#what&#39;s-next%3F&quot;&gt;What&#39;s next?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I spent a year and a half building this software, so I&#39;m obviously not giving up on it. Particle is a great product. In fact, I&#39;m using it to write this very post on my iPad and it truly is the best blogging experience I&#39;ve ever had. No bullshit. Inline editing is awesome!&lt;/p&gt;
&lt;p&gt;But I&#39;ve realized that trying to jumpstart this project by crowdfunding isn&#39;t as appealing as it once was. Yes, the software is fully functional, but there are still things I&#39;d like to improve before I send it off into the world. Having a big chunk of money isn&#39;t worth the added stress of deadlines to meet and backers (micro-investors?) to answer to. More importantly, wasting another month trying to get that chunk of money seems more and more ridiculous with each day I spend emailing Mashable and pissing people off on Twitter. Particle will be ready when it&#39;s ready, and that&#39;s how it should have been all along.&lt;/p&gt;
&lt;p&gt;I would still like to open source Particle and turn it into a sustainable business. On the other hand, I have a family to feed and a lot of time vested in this project. I can&#39;t afford to give away nearly two years of work with absolutely no way to monetize it. That would leave us with no food on the table and no money to continue working on Particle, which means we starve, the project fizzles out, and everyone loses.&lt;/p&gt;
&lt;p&gt;Particle needs a premium service or some alternative way to make it sustainable before it can be open sourced.&lt;/p&gt;
&lt;h2 id=&quot;there&#39;s-a-light&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/lessons-from-a-failed-kickstarter/#there&#39;s-a-light&quot;&gt;There&#39;s a light&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I do have some great news: I&#39;ve teamed up with a good friend who also happens to be one of the best developers I know. After studying Particle&#39;s code, he&#39;s decided to come onboard to help out with development. This will definitely help speed things up! We&#39;ll be taking some time this week to discuss the best approach for releasing Particle, be it open source, SaaS, or a combination of both. Anything is game at this point. Except fucking crowdfunding.&lt;/p&gt;
&lt;p&gt;For those of you who backed Particle, please get in touch with me on Twitter or email (cory at this domain) — I have some stickers for you. For everyone else, you can either follow Particle on Twitter or signup for the mailing list to stay up to date.&lt;/p&gt;
&lt;p&gt;Even though Particle wasn&#39;t a good fit for Kickstarter, we&#39;re still going to bring inline editing to blogging. It&#39;s coming. It&#39;s just a matter of time now.&lt;/p&gt;
&lt;p&gt;— Go forth and create!&lt;/p&gt;
&lt;p&gt;Update: Particle has been renamed to Postleaf and is now available at &lt;a href=&quot;http://postleaf.org/&quot;&gt;postleaf.org&lt;/a&gt;.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Democratizing publishing</title>
		<link href="https://www.abeautifulsite.net/posts/democratizing-publishing/"/>
		<updated>2016-03-28T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/democratizing-publishing/</id>
		<content type="html">&lt;p&gt;One of the objectives Matt Mullenweg has for WordPress is to &lt;a href=&quot;http://www.inc.com/glenn-leibowitz/meet-the-ceo-running-a-billion-dollar-company-with-no-offices-or-email.html&quot;&gt;democratize publishing&lt;/a&gt;, which is excellent. But the very same article states another objective is to &amp;quot;capture the 75 percent of the internet that WordPress doesn&#39;t already manage.&amp;quot;&lt;/p&gt;
&lt;p&gt;In my opinion, these goals conflict with each other. If Matt truly wanted to democratize publishing, he wouldn&#39;t be trying to monopolize it. That&#39;s how you destroy a democracy, not create one.&lt;/p&gt;
&lt;p&gt;Of course, WordPress will never truly have 100% of the Internet, but the thought of closing in on that goal is very frightening. I&#39;ve been a developer long enough to remember all too well how &lt;a href=&quot;http://mashable.com/2009/07/16/ie6-must-die/&quot;&gt;Internet Explorer 6 stifled innovation for many years&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/breaking-bad-frightened.gif&quot; alt=&quot;Walter White Frightened&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The same will happen as WordPress closes in on their goal, and that&#39;s exactly why we need more open source options like &lt;a href=&quot;https://ghost.org/&quot;&gt;Ghost&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Some words of wisdom from Nancy Pearcey:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Competition is always a good thing. It forces us to do our best. A monopoly renders people complacent and satisfied with mediocrity.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now, go forth and create!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Animated CSS hamburger icons</title>
		<link href="https://www.abeautifulsite.net/posts/animated-css-hamburger-icons/"/>
		<updated>2016-03-07T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/animated-css-hamburger-icons/</id>
		<content type="html">&lt;p&gt;If you need some tasty CSS hamburger icons that animate in fantastic ways, here you go.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jonsuh.com/hamburgers/&quot;&gt;Hamburgers&lt;/a&gt; is an MIT-licensed CSS library that gives you over a dozen beautifully animated navicons for use in your own projects. Also includes the Sass source so you can customize and compile it yourself.&lt;/p&gt;
&lt;p&gt;This is a beautiful little library!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Flushing DNS cache on macOS</title>
		<link href="https://www.abeautifulsite.net/posts/flush-dns-cache-on-os-x/"/>
		<updated>2016-03-02T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/flush-dns-cache-on-os-x/</id>
		<content type="html">&lt;p&gt;Here&#39;s the best way to flush DNS cache on macOS:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; dscacheutil -flushcache&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;killall&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-HUP&lt;/span&gt; mDNSResponder&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; say cache flushed&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice that last part — that&#39;s why this is the best method. You get an audible &amp;quot;cache flushed&amp;quot; almost instantaneously, and the whole process becomes that much more satisfying.&lt;/p&gt;
&lt;p&gt;Another fun variation:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; dscacheutil -flushcache&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;killall&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-HUP&lt;/span&gt; mDNSResponder&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; say booyah&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Have at it. It may be silly, but it&#39;s the little things in life. Now, go flush that DNS!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>A clean fade-in effect for webpages</title>
		<link href="https://www.abeautifulsite.net/posts/a-clean-fade-in-effect-for-webpages/"/>
		<updated>2015-09-23T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/a-clean-fade-in-effect-for-webpages/</id>
		<content type="html">&lt;p&gt;Here&#39;s a nice way to fade your pages in using CSS and a bit of JavaScript. The solution is clean and smooth, with no flickering on load. If JavaScript is disabled, the page will still load but the fade effect will not occur.&lt;/p&gt;
&lt;h2 id=&quot;how-it-works&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/a-clean-fade-in-effect-for-webpages/#how-it-works&quot;&gt;How it works&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This trick works by adding the &lt;code&gt;fade-out&lt;/code&gt; class to your &lt;code&gt;body&lt;/code&gt; with a script, then removing it when the page is done loading. The fade effect is handled completely with CSS. We&#39;re only using JavaScript to add/remove the class, which will ensure the page still displays if scripts are disabled.&lt;/p&gt;
&lt;h2 id=&quot;the-css&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/a-clean-fade-in-effect-for-webpages/#the-css&quot;&gt;The CSS&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We start with two very simple styles for the body:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;transition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1s opacity&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;body.fade-out&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;transition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;the-javascript&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/a-clean-fade-in-effect-for-webpages/#the-javascript&quot;&gt;The JavaScript&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now we need to add the &lt;code&gt;fade-out&lt;/code&gt; class to the body as soon as the page loads. We can do this with an inline script right after the opening &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; tag:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;
  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;classList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;fade-out&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The inline script is necessary (as opposed to a script loaded from a separate file) to prevent flickering, as the body would otherwise be briefly visible until the extra script is downloaded by the browser.&lt;/p&gt;
&lt;p&gt;Now we just need to remove the &lt;code&gt;fade-out&lt;/code&gt; class from the body once the page is loaded.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;DOMContentLoaded&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;classList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;fade-out&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;changing-the-fade-color&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/a-clean-fade-in-effect-for-webpages/#changing-the-fade-color&quot;&gt;Changing the fade color&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By default, the user will see a blank white screen until the page fades in. This is customizable through the &lt;code&gt;html&lt;/code&gt; selector:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; black&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;tips&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/a-clean-fade-in-effect-for-webpages/#tips&quot;&gt;Tips&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Don&#39;t get too carried away with this. It&#39;s a useful effect for loading something like a homepage, but it can quickly get annoying if you apply it to every page. Keep it subtle. Users shouldn&#39;t actually notice it — it should simply be a pleasant part of their experience.&lt;/p&gt;
&lt;p&gt;This is a really helpful trick if you need to wait for an image or video to load. However, in that case you&#39;ll probably want to add a loader. To achieve this, simply add a wrapper element around everything except the loader and apply the &lt;code&gt;fade-out&lt;/code&gt; class to that instead of the body.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>How to remove box shadows from input controls on iOS</title>
		<link href="https://www.abeautifulsite.net/posts/how-to-remove-box-shadows-from-input-controls-on-ios/"/>
		<updated>2015-09-16T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/how-to-remove-box-shadows-from-input-controls-on-ios/</id>
		<content type="html">&lt;p&gt;Those default box shadows that appear inside of your input elements on iOS can be pretty annoying, especially if you&#39;re going for a flat or subtle look. Here&#39;s how to remove them.&lt;/p&gt;
&lt;p&gt;Unfortunately, it&#39;s not as simple as setting the &lt;code&gt;box-shadow&lt;/code&gt; property to &lt;code&gt;none&lt;/code&gt;. Instead, you have to alter the &lt;code&gt;-webkit-appearance&lt;/code&gt; property:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;input[type=text],
input[type=email],
input[type=password],
textarea&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;-webkit-appearance&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That gets rid of the shadow but, for best results, you&#39;ll probably want to set your own border, background, and — perhaps ironically — your own box shadow.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Passing data from PHP to JavaScript</title>
		<link href="https://www.abeautifulsite.net/posts/passing-data-from-php-to-javascript/"/>
		<updated>2015-03-05T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/passing-data-from-php-to-javascript/</id>
		<content type="html">&lt;p&gt;Have you ever needed to send a PHP variable, array, or object to JavaScript? It can get complicated trying to escape the output properly. Here&#39;s a way that always works — no escaping necessary.&lt;/p&gt;
&lt;p&gt;Let&#39;s say we have the following variable in PHP:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$name&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;Bob Marley&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And we want to pass it to a JavaScript variable called &lt;code&gt;name&lt;/code&gt;. Here&#39;s the trick:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&amp;lt;script&gt;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;var name = &#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;json_encode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&amp;lt;/script&gt;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using &lt;code&gt;json_encode()&lt;/code&gt;, you&#39;ll always get a properly formatted JavaScript object.&lt;/p&gt;
&lt;p&gt;The same trick can be applied to other data types (e.g. integers, arrays, objects, etc.). The following passes an entire array from PHP to JavaScript:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$shirt&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;color&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;blue&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;number&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;23&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;size&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;XL&#39;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&amp;lt;script&gt;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;var shirt = &#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;json_encode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$shirt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&amp;lt;/script&gt;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The output looks like this:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; shirt &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string-property property&quot;&gt;&quot;color&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;blue&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string-property property&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;23&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string-property property&quot;&gt;&quot;size&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;XL&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Don&#39;t want it all on one line? Try this instead:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;&amp;lt;script&gt;&#92;n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;var shirt = &#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;json_encode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$shirt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON_PRETTY_PRINT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;&#92;n&amp;lt;/script&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The output is a bit easier to read:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; shirt &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&quot;color&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;blue&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&quot;size&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;XL&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A simple trick, but nevertheless useful.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>The HTML5 download attribute</title>
		<link href="https://www.abeautifulsite.net/posts/the-html5-download-attribute/"/>
		<updated>2015-02-19T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/the-html5-download-attribute/</id>
		<content type="html">&lt;p&gt;Years ago I showed you how to &lt;a href=&quot;https://www.abeautifulsite.net/posts/forcing-file-downloads-in-php&quot;&gt;force a file to download with PHP&lt;/a&gt;. Now with HTML5, you [almost] don&#39;t have to do that anymore.&lt;/p&gt;
&lt;p&gt;The HTML5 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#Attributes&quot;&gt;download attribute&lt;/a&gt; is intended to tell the browser that a certain link should force a certain file to download, optionally with a certain name that might be different than that on the server. Here&#39;s what it looks like:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/path/to/file.txt&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;download&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;any-name-you-want.txt&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Download&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will tell your browser to download &lt;code&gt;file.txt&lt;/code&gt; and prefill the name to &lt;code&gt;any-name-you-want.txt&lt;/code&gt;. No fancy server-side code required. As Mozilla notes, you can also use this technique with data URLs.&lt;/p&gt;
&lt;p&gt;Now, of course, the caveat. &lt;a href=&quot;http://caniuse.com/#feat=download&quot;&gt;Internet Explorer doesn&#39;t support it&lt;/a&gt;, and creating a polyfill &lt;a href=&quot;http://stackoverflow.com/questions/18652750/any-fallback-client-side-solutions-for-the-html5-download-attribute&quot;&gt;isn&#39;t really possible&lt;/a&gt;. Although you could probably use a combination of feature detection and a proxy server to force the download, but that&#39;s really more effort than it&#39;s worth.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Get comfortable with abstraction</title>
		<link href="https://www.abeautifulsite.net/posts/get-comfortable-with-abstraction/"/>
		<updated>2015-02-18T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/get-comfortable-with-abstraction/</id>
		<content type="html">&lt;p&gt;I stumbled across &lt;a href=&quot;https://twitter.com/ossia/status/565907210497040384/photo/1&quot;&gt;a tweet&lt;/a&gt; the other day and it&#39;s been resonating in my mind ever since. Mostly because it&#39;s something I tend to have a problem with.&lt;/p&gt;
&lt;p&gt;You see, I have this thing where I try really hard to understand exactly how something works — all the way down to the last nut and bolt. Deep down I know that those details are usually irrelevant. But it bothers me to know there are things that I don&#39;t know.&lt;/p&gt;
&lt;p&gt;I have a problem with abstraction.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/abstraction-comic.png&quot; alt=&quot;A comic strip about a person describing something while another person asks question after question&quot; /&gt;&lt;/p&gt;
&lt;p&gt;So I&#39;m posting this comic as a reminder for myself to look beyond the details and focus on the big picture. Maybe you&#39;ll enjoy reading it too.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Comic courtesy of &lt;a href=&quot;http://abstrusegoose.com/98&quot;&gt;Abtruse Goose&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Thoughts on being a good manager</title>
		<link href="https://www.abeautifulsite.net/posts/thoughts-on-being-a-good-manager/"/>
		<updated>2015-02-09T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/thoughts-on-being-a-good-manager/</id>
		<content type="html">&lt;p&gt;Some thoughts I had after conversations with a friend who has a terrible manager. This isn&#39;t nearly a comprehensive list, but it highlights many of the problems they were experiencing. Maybe my friend&#39;s manager will stumble upon it some day.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When someone has a grievance, take an objective stance.&lt;/strong&gt; Listen to them, understand what they&#39;re trying to tell you, and react accordingly. Don’t deny issues that really are issues, and don’t ignore them in hopes that the problems just go away. They won’t. They’ll just snowball into bigger issues.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You’re the manager.&lt;/strong&gt; You’re in charge of making sure the organization is running smoothly. If an employee is faltering, it’s your job to step in and help get things back up to speed. Don’t expect everyone else to pick up the slack — they have a lot of work to do too. As a manager, you’ll gain a lot of respect for getting “down in the trenches” when the team really needs you.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Discipline employees when they need to be disciplined.&lt;/strong&gt; Have a plan in place and follow it for everyone. No exceptions, otherwise you risk enabling abusers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Don’t be afraid of confrontation.&lt;/strong&gt; This is a sign of weakness, and cunning employees will take advantage of it time after time. When the moment comes, stand your ground, explain the problem clearly, and be prepared to offer a solution.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Realize when something is out of an employee’s control&lt;/strong&gt; (e.g. bereavement leave) versus under an employee’s control (e.g. personal appointments). In case of the latter, insist they try to make time for it outside of their normal work schedule. If that’s not possible, require them to make up missed time before work, after work, or during lunch. This compromise asserts the employee’s value to the organization and will significantly reduce absenteeism.&lt;/p&gt;
&lt;p&gt;Nobody deserves preferential treatment, no matter who they are or what their situation is. Business is business, and if someone has committed to a position, they should honor that commitment or step down until they have the time and energy to resume their obligations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When you hire someone and train them for a position, let them do their job.&lt;/strong&gt; Correct them when mistakes are made, but if the job is being done correctly and with reasonable efficiency, don’t keep stepping in to micromanage them. This is frustrating for employees, and it’s also a trait of poor management skills.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Treat your employees like an investment:&lt;/strong&gt; pay them well and they will perform well. Don’t tell them that the organization doesn’t have enough money to provide raises — most employees are smarter than that. Give them what they’re worth and set goals for them to earn more. This will motivate them, reduce turnover, and show compassion. Your employees will remember that and will be more apt to stick around and do great work.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A workplace is like a team:&lt;/strong&gt; you have a group of people working together to achieve a common goal. Each player in a team has a specific purpose. When one of those players is underperforming or absent, the rest of the team has to make up for it. When this happens on a regular basis, morale suffers and players become disgruntled — some may even choose to quit. As the “team captain”, this is your fault — not theirs. Don’t let other players adversely affect the rest of the team. It’s your job to step in and keep everything in line.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Know when to let someone go.&lt;/strong&gt; It&#39;s always better for the organization and the employee to try to work things out. Alas, the time will come when an employee is no longer a good fit for their position and you need to be OK with letting them go. It&#39;s not the end of the world. In many cases the employee will find a new job that suits them even better. If nothing else, being let go is an eye opener that can actually help them become a better employee at their next job.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;At the end of the day, you&#39;re the manager.&lt;/strong&gt; How your organization operates is a reflection of you. So here&#39;s something to keep in mind. It&#39;s a quote from Napoleon that I hope will resonate in your thoughts for the rest of your management career: &amp;quot;An army of lions commanded by a deer will never be an army of lions.&amp;quot;&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>I should have been asking my users this from the start</title>
		<link href="https://www.abeautifulsite.net/posts/i-should-have-been-asking-my-users-this-from-the-start/"/>
		<updated>2015-01-20T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/i-should-have-been-asking-my-users-this-from-the-start/</id>
		<content type="html">&lt;p&gt;Feedback is critical to an app&#39;s success. How will you know what to fix or improve on if your users don&#39;t tell you? It seems obvious, but here is something I should have been asking my users from the start.&lt;/p&gt;
&lt;h2 id=&quot;getting-the-right-feedback-is-critical&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/i-should-have-been-asking-my-users-this-from-the-start/#getting-the-right-feedback-is-critical&quot;&gt;Getting the right feedback is critical&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When someone signs up for my service, they get a nice welcome message that thanks them for signing up and shows them how to login. Inside that message, there&#39;s also a line that reads something like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you have any questions or suggestions, hit &lt;em&gt;reply&lt;/em&gt; and let us know!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This lets people know that we&#39;re open to suggestions (which should be a given for a SaaS app), but it really doesn&#39;t produce a lot of useful feedback. I think people are desensitized by lines like that, but the message feels a lot less friendly without it.&lt;/p&gt;
&lt;p&gt;I also send follow up emails after a couple days. I&#39;m not trying to sell them something at this point — I&#39;m trying to see if they&#39;re having trouble with the app or if they have any questions or feedback for me. This tends to yield a better response, especially when I ask about the user&#39;s business and what they expect from my service.&lt;/p&gt;
&lt;p&gt;However, the single most important piece of feedback is something that I didn&#39;t start collecting until a few days ago.&lt;/p&gt;
&lt;h2 id=&quot;a-simple-oversight&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/i-should-have-been-asking-my-users-this-from-the-start/#a-simple-oversight&quot;&gt;A simple oversight&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In my app, users can cancel their subscription or delete their account on their own — no need to email in a request. I do this because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I don&#39;t believe in retention via guilt (i.e. begging users to give it another try)&lt;/li&gt;
&lt;li&gt;It&#39;s more convenient for them&lt;/li&gt;
&lt;li&gt;It&#39;s less to manage for me&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But what I was missing out on is the feedback that comes from when a user decides to cancel or delete his account. This is very, very important for a SaaS company. How in the world was I not collecting this data?&lt;/p&gt;
&lt;p&gt;The truth is I was trying, but I was going about it all wrong. For awhile now, whenever somebody canceled or deleted their account, the app would send me an email so I could follow up with them to find out why. I thought this would be more personal, as every message I typed was by hand. I almost never got responses to those emails.&lt;/p&gt;
&lt;p&gt;Looking back, that&#39;s probably because those users had already disconnected from the service. By the time they received my email, they had already moved on and didn&#39;t want to waste anymore of their time on it. It was simply too little, too late.&lt;/p&gt;
&lt;h1 id=&quot;a-better-way-to-ask-users&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/i-should-have-been-asking-my-users-this-from-the-start/#a-better-way-to-ask-users&quot;&gt;A better way to ask users&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;It became obvious that I needed to find a better way to ask users for their feedback &lt;em&gt;before&lt;/em&gt; they canceled their accounts. So I recently took some time and added a simple text field to the cancel/delete screens. Not a dropdown menu, not radio buttons — just a simple textbox where they can leave one word or 1,000 words. By reaching out to users who are in the process of canceling, I&#39;ve found that they&#39;re much more likely to voice their reasons.&lt;/p&gt;
&lt;p&gt;Since I&#39;ve made that simple change, I went from almost zero feedback to &lt;em&gt;all but one user&lt;/em&gt; telling me why they decided to cancel. (For what it&#39;s worth, the person who didn&#39;t leave a reason had only signed up a few minutes prior to canceling the account — probably just a window shopper.)&lt;/p&gt;
&lt;p&gt;Even though it&#39;s only been a few days, I&#39;ve learned a lot about why users decide to cancel their accounts. It gives me a better understanding of how they work, how they think, and what they expect, and it gives them a chance to have their voices heard.&lt;/p&gt;
&lt;p&gt;What I found was a better way to ask my users for feedback. It&#39;s so ridiculously simple. I just wish I&#39;d thought to do it years ago.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Why developers hate being interrupted</title>
		<link href="https://www.abeautifulsite.net/posts/why-developers-hate-being-interrupted/"/>
		<updated>2015-01-08T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/why-developers-hate-being-interrupted/</id>
		<content type="html">&lt;p&gt;I stumbled across a post today (that unfortunately no longer exists) and I was almost convinced that I had written it myself. Many of the points in it hit home, so I hope it helps people better understand how developers think and what they go through when interruptions arise.&lt;/p&gt;
&lt;p&gt;One point talks about how much headwork programming requires:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A huge amount of what a developer is doing is in their head. As we write code we need to keep a mental model of how parts of the application that have already been written and are yet to be written interact with the part that we are writing at that moment. We need to have a solid picture of exactly how the code is working as a whole and maintain that picture. It’s not easy, it requires a lot of concentration and has to remain in place while we think of creative and efficient ways to solve the problem at hand.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Another explains why developers are actually the most productive when they seem unproductive:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Developers can appear very unproductive at times, sitting staring at the screen with our headphones on and very little in the way of keyboard clackety-tap. This however is when we are doing our thinking, when we are building up, adding to and rearranging the mental model of how our code will work. This is the biggest and hardest part of development.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It&#39;s so true. Breaking a developer&#39;s concentration can be devastating to their productivity.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Social sharing buttons are ineffective</title>
		<link href="https://www.abeautifulsite.net/posts/social-sharing-buttons-are-ineffective/"/>
		<updated>2014-12-16T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/social-sharing-buttons-are-ineffective/</id>
		<content type="html">&lt;p&gt;Back in 2012, I wrote an article called &lt;a href=&quot;http://www.abeautifulsite.net/down-with-the-share-widget/&quot;&gt;Down with the &amp;quot;Share&amp;quot; Widget.&lt;/a&gt; In it, I talked about why plastering social sharing buttons all over your website is completely ineffective. This morning, Smashing Magazine all but confirmed my theory.&lt;/p&gt;
&lt;p&gt;In today&#39;s &lt;a href=&quot;http://www.smashingmagazine.com/smashing-newsletter-issue-127/&quot;&gt;Smashing Newsletter&lt;/a&gt;, they wrote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Are social sharing buttons really that effective to be placed in the most visible areas of websites, sometimes even as &lt;a href=&quot;https://twitter.com/smashingmag/status/544446915493261312&quot;&gt;“sticky&amp;quot; notes&lt;/a&gt; on the left or on the right side of the page? Are there any case studies which provide proof that these social icons are actually effective? Or are they indeed &lt;a href=&quot;https://twitter.com/smashingmag/status/544446915493261312&quot;&gt;ineffective&lt;/a&gt;, &lt;a href=&quot;http://smashingmagazine.us1.list-manage1.com/track/click?u=16b832d9ad4b28edf261f34df&amp;amp;id=9bc67d4ace&amp;amp;e=52f5f3af5b&quot;&gt;barely used&lt;/a&gt; and really just &lt;a href=&quot;http://smashingmagazine.us1.list-manage.com/track/click?u=16b832d9ad4b28edf261f34df&amp;amp;id=8dbd2681d4&amp;amp;e=52f5f3af5b&quot;&gt;annoying&lt;/a&gt;?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;While their stance isn&#39;t conclusive, the fact that they even raised the question says quite a bit. Are people are finally becoming desensitized to all the Facebook and Twitter logos everywhere? Maybe now that social media is commonplace, we can all get back to writing better content instead of designing trendy new share widgets.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>How to use currentColor in your stylesheet</title>
		<link href="https://www.abeautifulsite.net/posts/how-to-use-currentcolor-in-your-stylesheet/"/>
		<updated>2014-12-04T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/how-to-use-currentcolor-in-your-stylesheet/</id>
		<content type="html">&lt;p&gt;I&#39;ve had my head buried so deep in code that I hadn&#39;t even noticed this existed. It&#39;s a simple way to reference the current text color when writing CSS. Works in modern browsers, including IE9+.&lt;/p&gt;
&lt;p&gt;If you use Less or Sass then you probably already use something like &lt;code&gt;@text-color&lt;/code&gt;. Alas, CSS doesn&#39;t have variables yet, but &lt;code&gt;currentColor&lt;/code&gt; will come in handy if you&#39;re tired of repeating the same hex codes over and over again. Here&#39;s how it works:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #00f&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; solid 2px currentColor&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That will produce a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; with blue text and a matching blue border around it. If you need to change it later on, you only need to change it in one place.&lt;/p&gt;
&lt;p&gt;Of course, you can use currentColor for other properties too. Box shadows, background colors — pretty much anything. You can even use &lt;code&gt;currentColor&lt;/code&gt; with pseudo elements:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #00f&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;div::after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/*
     Styles for CSS triangles or anything else
     you&#39;d use a pseudo element for go here
  */&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;border-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; currentColor&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The resulting &lt;code&gt;border-color&lt;/code&gt; will be taken from the &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;, which in this case is &lt;code&gt;#00f&lt;/code&gt;.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>I switched from tabs to spaces and haven&#39;t looked back</title>
		<link href="https://www.abeautifulsite.net/posts/i-switched-from-tabs-to-spaces-and-havent-looked-back/"/>
		<updated>2014-11-25T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/i-switched-from-tabs-to-spaces-and-havent-looked-back/</id>
		<content type="html">&lt;p&gt;Last week I started using spaces to indent code instead of tabs. It&#39;s something I swore I would never do, but I&#39;m glad I finally did.&lt;/p&gt;
&lt;h2 id=&quot;why-i-always-preferred-tabs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/i-switched-from-tabs-to-spaces-and-havent-looked-back/#why-i-always-preferred-tabs&quot;&gt;Why I always preferred tabs&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Tabs are sensible. They were made to indent things, and code needs to be indented, so it was a good relationship. Probably the two most well-known arguments for using tabs are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tabs reduce file size (although this is negligible and I would never argue based on this point)&lt;/li&gt;
&lt;li&gt;Tabs allow each developers to choose their own indentation level without changing the actual file (this was always my biggest reason, and I think most pro-tab people agree)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Of course, there are more arguments (and plenty for spaces too), but here&#39;s why &lt;em&gt;I&#39;ve&lt;/em&gt; switched.&lt;/p&gt;
&lt;h2 id=&quot;soft-tabs-make-it-seamless&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/i-switched-from-tabs-to-spaces-and-havent-looked-back/#soft-tabs-make-it-seamless&quot;&gt;Soft tabs make it seamless&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Most editors support soft tabs, which means you can still use the tab key to indent/outdent and never even notice the difference. Sublime Text 3 is my editor of choice, and it does a superb job of this. It also has some built in tools for converting between tabs and spaces, reindenting, etc. That made it a lot easier for me to switch and update existing files.&lt;/p&gt;
&lt;p&gt;And when I &amp;quot;seamless&amp;quot;, it really has been. I&#39;ve been a stubborn tab guy for like a decade. My workflow hasn&#39;t changed, the keystrokes I use are identical, the code looks the same, and the universe hasn&#39;t imploded yet. That&#39;s a good sign for my first week.&lt;/p&gt;
&lt;h2 id=&quot;indentation-is-always-consistent&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/i-switched-from-tabs-to-spaces-and-havent-looked-back/#indentation-is-always-consistent&quot;&gt;Indentation is always consistent&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One thing that always drove me crazy about using tabs was the way HTML looks when you view the source. Most browsers render tabs the equivalent of eight or more spaces long. Why they do this, I&#39;ll never know. But I do know that I don&#39;t have to worry about that anymore. +1 for spaces.&lt;/p&gt;
&lt;p&gt;There are other places where indentation varies. In fact, the biggest pro-tab argument ends up being an argument &lt;em&gt;against&lt;/em&gt; tabs when you don&#39;t have control over how deep indentations go.&lt;/p&gt;
&lt;h2 id=&quot;everyone-uses-them-now&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/i-switched-from-tabs-to-spaces-and-havent-looked-back/#everyone-uses-them-now&quot;&gt;Everyone uses them now&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://getbootstrap.com/&quot;&gt;Bootstrap&lt;/a&gt; is massively popular, and for a good reason. It cuts out the fat and gives you something tried and tested to develop with. It&#39;s a solid framework, and the conventions they use make really good sense.&lt;/p&gt;
&lt;p&gt;So when Mark Otto (probably best known as &lt;a href=&quot;https://twitter.com/mdo&quot;&gt;@mdo&lt;/a&gt;) released his &lt;a href=&quot;http://codeguide.co/&quot;&gt;code guide&lt;/a&gt;, it of course suggested we use soft tabs (spaces). Another hard blow to tab lovers.&lt;/p&gt;
&lt;p&gt;Here&#39;s the thing — I normally wouldn&#39;t sway and I&#39;d keep doing my own thing code rogue style, but what&#39;s the point? If you&#39;ve ever been on GitHub, it&#39;s clear that most developers are using spaces now. As tab lovers, we&#39;re pissing into the wind.&lt;/p&gt;
&lt;p&gt;So last week I decided to try out spaces while building &lt;a href=&quot;http://www.particle.software/&quot;&gt;Particle&lt;/a&gt;. I converted all files from tabs to spaces in less than five minutes and just went with it. And I actually liked it. A lot.&lt;/p&gt;
&lt;h2 id=&quot;my-code-fits-in-now&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/i-switched-from-tabs-to-spaces-and-havent-looked-back/#my-code-fits-in-now&quot;&gt;My code fits in now&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It&#39;s refreshing to know that my code fits in better with other people&#39;s code now. I don&#39;t have to worry about what other developers and projects are using, because most of them are using spaces anyway. I also don&#39;t have to worry about contributing to a project and accidentally sending commits with a mix of tabs and spaces.&lt;/p&gt;
&lt;p&gt;Call it peer pressure. Call it giving up on my beloved tabs. I really don&#39;t care anymore. At the end of the day, I looked past an old habit and, for whatever reason, I decided to try something new.&lt;/p&gt;
&lt;p&gt;I switched from tabs to spaces and haven&#39;t looked back.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>CSS shapes are here</title>
		<link href="https://www.abeautifulsite.net/posts/css-shapes-are-here/"/>
		<updated>2014-10-16T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/css-shapes-are-here/</id>
		<content type="html">&lt;p&gt;Here&#39;s something exciting from the CSS world: shapes!&lt;/p&gt;
&lt;p&gt;Ok, it may not sound all that exciting, but you haven&#39;t had a chance to see what can actually be done with CSS shapes yet. (Hint: check out the featured image above.)&lt;/p&gt;
&lt;p&gt;Razvan Caliman &lt;a href=&quot;http://www.html5rocks.com/en/tutorials/shapes/getting-started/&quot;&gt;explains it&lt;/a&gt; like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For a long time, web designers have been forced to create within the constraints of the rectangle. Most content on the web is still trapped in simple boxes because most creative ventures into non-rectangular layout end in frustration.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It&#39;s true. We didn&#39;t even get &amp;quot;circles&amp;quot; until &lt;code&gt;border-radius&lt;/code&gt; came around, and even then you&#39;d have to expect IE8 and below to fallback to a square. We&#39;ve been confined to boxes for a long time.&lt;/p&gt;
&lt;p&gt;So how are things changing? &lt;a href=&quot;http://www.html5rocks.com/en/tutorials/shapes/getting-started/&quot;&gt;See for yourself&lt;/a&gt; over at HTML5 Rocks. It&#39;s the best intro to CSS shapes I&#39;ve seen so far.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>CSS reset with box-sizing fix</title>
		<link href="https://www.abeautifulsite.net/posts/css-reset-with-box-sizing-fix/"/>
		<updated>2014-10-14T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/css-reset-with-box-sizing-fix/</id>
		<content type="html">&lt;p&gt;For ultra lightweight projects where a framework is overkill, I tend to use &lt;a href=&quot;http://meyerweb.com/eric/tools/css/reset/&quot;&gt;Eric Meyers&#39; CSS reset&lt;/a&gt;. And since I&#39;m not a glutton for punishment, I also throw in the tried and tested &lt;a href=&quot;http://www.paulirish.com/2012/box-sizing-border-box-ftw/&quot;&gt;box-sizing fix&lt;/a&gt; popularized by Paul Irish. Instead of searching for and combining these snippets every time I need them, here&#39;s a paste-ready version for convenience.&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* CSS reset with box-sizing fix */&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
 &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
 &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
 &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
 &lt;span class=&quot;token property&quot;&gt;font&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; inherit&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
 &lt;span class=&quot;token property&quot;&gt;vertical-align&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; baseline&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; block&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token property&quot;&gt;box-sizing&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; border-box&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;*, *:before, *:after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token property&quot;&gt;box-sizing&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; inherit&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token property&quot;&gt;line-height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;ol, ul&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token property&quot;&gt;list-style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;blockquote, q&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token property&quot;&gt;quotes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;blockquote:before, blockquote:after,
q:before, q:after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
 &lt;span class=&quot;token property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;table&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token property&quot;&gt;border-collapse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; collapse&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
 &lt;span class=&quot;token property&quot;&gt;border-spacing&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No attribution necessary, as this code is considered public domain. Just copy and paste it into your new stylesheet and start designing!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>What can you do with a single &lt;div&gt;?</title>
		<link href="https://www.abeautifulsite.net/posts/what-can-you-do-with-a-single-div/"/>
		<updated>2014-09-05T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/what-can-you-do-with-a-single-div/</id>
		<content type="html">&lt;p&gt;If I told you to make something using only CSS and a single &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;, would you be able to create something incredible?&lt;/p&gt;
&lt;p&gt;That&#39;s exactly what &lt;a href=&quot;https://twitter.com/lynnandtonic&quot;&gt;Lynn Fisher&lt;/a&gt; has been doing with &lt;a href=&quot;http://a.singlediv.com/&quot;&gt;A Single Div&lt;/a&gt;. Using only a single HTML element and some CSS, she&#39;s created some shockingly complex artwork ranging from Super Mario mushrooms to the iPhone&#39;s charging indicator. There&#39;s also a Bloody Mary, a breakfast plate, a crayon, a digital camera, and more.&lt;/p&gt;
&lt;p&gt;It&#39;s great inspiration and a heck of an argument against superfluous markup. &lt;a href=&quot;http://a.singlediv.com/&quot;&gt;Check it out&lt;/a&gt; and let me know if you think you can create something similar using only a single &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Stop trying to build the next unicorn</title>
		<link href="https://www.abeautifulsite.net/posts/stop-trying-to-build-the-next-unicorn/"/>
		<updated>2014-09-02T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/stop-trying-to-build-the-next-unicorn/</id>
		<content type="html">&lt;p&gt;So, you&#39;re building the next big thing? You say you&#39;re going to make millions and have a fancy office building out in the valley? That&#39;s cool. By the same odds we&#39;ll both be rich, because I&#39;m holding tonight&#39;s winning lotto ticket.&lt;/p&gt;
&lt;h2 id=&quot;your-idea-probably-won&#39;t-be-the-next-big-thing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/stop-trying-to-build-the-next-unicorn/#your-idea-probably-won&#39;t-be-the-next-big-thing&quot;&gt;Your idea probably won&#39;t be the next big thing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It&#39;s true. The odds are against you. Whatever you&#39;re building probably won&#39;t be the next Facebook or Twitter, but that doesn&#39;t mean you can&#39;t make a living doing what you love.&lt;/p&gt;
&lt;p&gt;It sounds discouraging, but I&#39;m really just trying to bring you down to earth. Stop reading all those articles about multi-million dollar funding rounds and IPOs. They&#39;re exciting. They trigger ambition. But they&#39;re not realistic. You might as well be reading about last night&#39;s lottery winner.&lt;/p&gt;
&lt;p&gt;You&#39;re probably well aware that &lt;a href=&quot;http://www.businessinsider.com/startup-odds-of-success-2013-5&quot;&gt;most startups fail&lt;/a&gt;. It&#39;s a vicious world out there with entrepreneurs trying desperately to get their ideas funded. They have an exit strategy even before they have a product. Building something great has taken a backseat to trying to become a billionaire.&lt;/p&gt;
&lt;h2 id=&quot;success-may-not-be-what-you-think-it-is&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/stop-trying-to-build-the-next-unicorn/#success-may-not-be-what-you-think-it-is&quot;&gt;Success may not be what you think it is&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When someone says &amp;quot;success&amp;quot;, what do you think of? Is it the money? The fame? The idea of retiring young? Is it having big houses and little cars? What type of lifestyle would you live if you were &amp;quot;successful&amp;quot; by your own standard?&lt;/p&gt;
&lt;p&gt;When we&#39;re young, we&#39;re taught to aim for the sky, but success doesn&#39;t have to be so glamourous. In fact, &lt;a href=&quot;http://blogs.wsj.com/wealth/2011/03/09/dont-envy-the-super-rich-they-are-miserable/&quot;&gt;rich people aren&#39;t as happy as you think&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If we can get people just a little bit more informed, so they know that getting the $20 million or $200 million won’t necessarily bring them all that they’d hoped for, then maybe they’d concentrate instead on things that would make the world a better place and could help to make them truly happy.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So what makes you truly happy?&lt;/p&gt;
&lt;h2 id=&quot;less-is-more&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/stop-trying-to-build-the-next-unicorn/#less-is-more&quot;&gt;Less is more&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;What if you could live in a comfortable house, have a nice car, work decent hours, enjoy the work you do, have a healthy budget for your day-to-day needs, and be able to spend more time with your family and friends? The average person would kill to have this life. (If you didn&#39;t know that already, you must be a very fortunate person.)&lt;/p&gt;
&lt;p&gt;The truth is, your success is based on many things that are important to you, not just your work. When you put too much focus on one thing, everything else ends up on the back burner. Working too much can &lt;a href=&quot;http://www.eharmony.com/blog/2013/05/30/psychological-profile-of-the-workaholic-how-working-too-much-ruins-relationships/&quot;&gt;ruin your relationship&lt;/a&gt; and even cause you to &lt;a href=&quot;http://www.forbes.com/sites/daviddisalvo/2012/09/12/why-working-more-than-8-hours-a-day-can-kill-you/&quot;&gt;die young&lt;/a&gt;. I wouldn&#39;t consider that to be very successful.&lt;/p&gt;
&lt;p&gt;So how do you reach that balance yet still be successful? There&#39;s nothing wrong with aiming high — just don&#39;t aim too high.&lt;/p&gt;
&lt;h2 id=&quot;there&#39;s-no-shame-in-a-lifestyle-business&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/stop-trying-to-build-the-next-unicorn/#there&#39;s-no-shame-in-a-lifestyle-business&quot;&gt;There&#39;s no shame in a lifestyle business&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Some people don&#39;t like the term &lt;a href=&quot;http://en.wikipedia.org/wiki/Lifestyle_business&quot;&gt;lifestyle business&lt;/a&gt;. If you&#39;re not familiar with it, a good definition is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A business that is set up and run by its founders primarily with the aim of sustaining a particular level of income and no more; or to provide a foundation from which to enjoy a particular lifestyle.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That&#39;s exactly what I started in 2008, albeit unknowingly. Of course, at the time, I was hoping my service would take off and be the next big thing — but it wasn&#39;t. It didn&#39;t make me millions of dollars and it didn&#39;t attract a group of check-writing VCs. But it also didn&#39;t crush my dreams. Rather, it enlightened me.&lt;/p&gt;
&lt;p&gt;You see, I ended up starting a sustainable business that&#39;s been paying my bills since 2008. I live the life I mentioned above, and I consider myself reasonably successful. I have a great service that I enjoy running, awesome users that I love helping, and there&#39;s nobody I have to report to at work. I take most weekends off and have plenty of time for family. In fact, I&#39;ll be celebrating my honeymoon for a week in the Caribbean next month. Life is good running a lifestyle business.&lt;/p&gt;
&lt;p&gt;Does that mean I won&#39;t reach a bit higher with my next project? Absolutely not. I&#39;d love to start another service that&#39;s just as (or more) successful than what I&#39;m doing now, but I&#39;m not going to let it dictate my life. The truth is, I&#39;m happy running a lifestyle business. I&#39;m not trying to build the next unicorn and, unless you like being disappointed, neither should you. You&#39;ll find much more success in launching something smaller.&lt;/p&gt;
&lt;p&gt;If you&#39;re stuck with that &amp;quot;go big or go home&amp;quot; mentality, my advice to you is figure out what you&#39;re good at, find a niche you enjoy, and start solving a problem. Grow your idea slowly but steadily, be good to your users, and stop worrying about becoming a millionaire. With your focus on building something you believe in, you&#39;ll have a much better chance of success and you just might end up with a business that will be around for years to come. That&#39;s way better than most startups do.&lt;/p&gt;
&lt;p&gt;And who knows? Maybe your idea will take you to the top. But if it doesn&#39;t, at least you&#39;ll still be doing something you love.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>BrowserStack: stop using virtual machines for browser testing</title>
		<link href="https://www.abeautifulsite.net/posts/browserstack-stop-using-virtual-machines-for-browser-testing/"/>
		<updated>2014-08-29T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/browserstack-stop-using-virtual-machines-for-browser-testing/</id>
		<content type="html">&lt;p&gt;Sick of booting up an entire virtual machine (VM) just to test something in IE? With &lt;a href=&quot;http://www.browserstack.com/&quot;&gt;BrowserStack&lt;/a&gt;, you don&#39;t need VMware or VirtualBox. Just enter a URL and instantly test on just about any browser you can think of.&lt;/p&gt;
&lt;p&gt;This is legit. It&#39;s not just another screenshot service or emulator. You have real-time access to an actual machine running your browser of choice. So how does it work? A BrowserStack engineer &lt;a href=&quot;http://www.quora.com/Web-Browsers/How-is-browserstack-com-implemented-How-does-it-emulate-various-browsers-within-a-single-browser&quot;&gt;explains&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;http://browserstack.com/&quot;&gt;BrowserStack.com&lt;/a&gt; works by connecting you with a real machine (let us call it server) running somewhere in one of our geographically distributed datacenters via RFB protocol.&lt;/p&gt;
&lt;p&gt;We use certain open source tools, modified to suit our needs, running on server side. Client browser runs a flash based client application which receives the input from the users and send it across the server. Server gets this input, does the required operation and sends the changes back to the client.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In other words, it&#39;s a clever way of remoting into a machine running the target browser, but you don&#39;t have to worry about VMs, memory, OS licensing, software updates, or even launching a browser.&lt;/p&gt;
&lt;p&gt;Sound too good to be true? I&#39;ve used it and it works really well. My biggest concern is that, even with a broadband connection, the remote screen gets a bit choppy (but this can also happen when you run a VM without enough memory). My other concern is the price. At &lt;a href=&quot;https://www.browserstack.com/pricing&quot;&gt;$39 a month&lt;/a&gt; for a solo plan, you need to be doing some serious browser testing to make it worth your while.&lt;/p&gt;
&lt;p&gt;Either way, it&#39;s worth checking out. They offer a free trial that gives you 30 minutes of live testing and 100 screenshots. I think you&#39;ll be impressed by what they&#39;ve built over at BrowserStack.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>I&#39;m taking &quot;startup&quot; back</title>
		<link href="https://www.abeautifulsite.net/posts/im-taking-startup-back/"/>
		<updated>2014-08-28T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/im-taking-startup-back/</id>
		<content type="html">&lt;p&gt;The word &amp;quot;startup&amp;quot; has taken on a very unfortunate meaning over the years. I used to think of my own business as a startup, but as its definition evolved, I quickly realized I didn&#39;t fit that description at all.&lt;/p&gt;
&lt;p&gt;The word &amp;quot;startup&amp;quot;, by definition, means the act or instance of setting in operation or motion. Or, more appropriately, a fledgling business enterprise. Given that, you could assume that just about any up and coming business is, in fact, a startup. But you&#39;d be wrong.&lt;/p&gt;
&lt;h2 id=&quot;what-it-means-today&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/im-taking-startup-back/#what-it-means-today&quot;&gt;What it means today&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While the definition will vary from entrepreneur to investor, there&#39;s one thing that most startups have in common these days: many seem to be in it for the money. You see, we&#39;re in the middle of a &lt;a href=&quot;http://www.usnews.com/news/articles/2014/02/24/facebook-apple-google-and-the-tech-startup-gold-rush&quot;&gt;gold rush&lt;/a&gt;, and everybody wants a piece of the pie.&lt;/p&gt;
&lt;p&gt;Back in the day, running a startup meant that you shared a certain passion and solved a certain problem. It was a culture, one that you submitted to because you wanted to make the world a better place. When you were a startup founder, the last thing on your mind was an exit strategy. Hell, &lt;a href=&quot;http://www.fastcompany.com/3032341/most-creative-people/this-startup-had-over-5-million-users-and-a-great-product-then-it-folde&quot;&gt;some didn&#39;t even have a monetization strategy&lt;/a&gt;. You just wanted to build something awesome and feel good knowing people used your product.&lt;/p&gt;
&lt;p&gt;That&#39;s not to say that making money isn&#39;t important — after all, you have to eventually monetize to stay in business — but sustainability is very different than superabundance. The problem now is that most people are taking that million dollar shot. They care less about what they&#39;re building, more about how they&#39;re going to get rich, and they&#39;re indifferent to the quality of their product.&lt;/p&gt;
&lt;p&gt;You can thank acquisitions like the &lt;a href=&quot;http://www.businessweek.com/articles/2012-04-09/facebook-snaps-up-instagram&quot;&gt;$1 billion Instagram deal&lt;/a&gt; or the absurdly high &lt;a href=&quot;http://www.businessweek.com/articles/2014-02-19/facebook-acquires-whatsapp-for-19-billion&quot;&gt;$19 billion WhatsApp purchase&lt;/a&gt;. Big companies are buying up products and services like they&#39;re going out of style, and each high-dollar acquisition just adds fuel to the fire. The idea of becoming a millionaire is poisoning the startup well.&lt;/p&gt;
&lt;p&gt;As a result, &amp;quot;startup&amp;quot; has become synonymous with a business whose primary goal is to make a bunch of money through investments, acquisitions, or the holy IPO grail. They&#39;re like the new get-rich-quick schemes.&lt;/p&gt;
&lt;h2 id=&quot;why-i&#39;m-taking-it-back&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/im-taking-startup-back/#why-i&#39;m-taking-it-back&quot;&gt;Why I&#39;m taking it back&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While my company doesn&#39;t share the same traits as those above, I always considered it to be a startup. I started bootstrapping it back in 2007 and, to this day, I haven&#39;t taken investments of any kind. To me, that&#39;s one of the most beautiful things about the startup world. You can create something from virtually nothing and, the next thing you know, you&#39;re running a profitable business.&lt;/p&gt;
&lt;p&gt;What starts as an idea evolves into a product or service, and it&#39;s made great by the passion you have for building it. But when you start thinking more about the money than the experience, you end up adding to the landfill of half-hearted products that nobody ever wanted. If you have an exit strategy before you have an idea, you&#39;re doing it for the wrong reason.&lt;/p&gt;
&lt;p&gt;For me, this issue came to light a few years ago when someone made me feel very ignorant for calling my own business a startup.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You run a startup? Who have you pitched your idea to? How much are you seeking for investment? What&#39;s your exit strategy?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;None of it applied to me, but the questions were asked with such certainty that it felt like they should have. That&#39;s become the expectation for startups these days. After I explained that I wasn&#39;t doing any of that, he responded with:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Oh, so you&#39;re not a startup. You&#39;re a bootstrapper.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Suddenly, my product wasn&#39;t interesting because I didn&#39;t plan on getting acquired or raising millions of dollars.&lt;/p&gt;
&lt;p&gt;In hindsight, I should have corrected him. You see, I&#39;ve come to realize that it&#39;s not my version of &amp;quot;startup&amp;quot; that&#39;s been skewed. It&#39;s those that think startups have only one purpose — to generate multi-million dollar payouts — who are getting it wrong.&lt;/p&gt;
&lt;p&gt;A startup isn&#39;t a wealth generator. Yes, one of their functions is to sustain a business financially, but that&#39;s not the reason you should be in the game. A startup is an idea. It&#39;s a passion. It&#39;s a culture. It&#39;s a business that aspires to make the world better, no matter how large or small.&lt;/p&gt;
&lt;p&gt;From now on, when you hear me talk about startups, don&#39;t be confused by the people who are starting up just to cash out. Know that when I use the &amp;quot;s&amp;quot; word, I&#39;m referring to those who are doing what they love for reasons that amount to much more than just dollar signs.&lt;/p&gt;
&lt;p&gt;I&#39;m drilling a new well. I&#39;m tossing out the trash. I&#39;m taking &amp;quot;startup&amp;quot; back.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Hide the mouse cursor with CSS</title>
		<link href="https://www.abeautifulsite.net/posts/hide-the-mouse-cursor-with-css/"/>
		<updated>2014-08-28T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/hide-the-mouse-cursor-with-css/</id>
		<content type="html">&lt;p&gt;I know you can change the mouse cursor using CSS, but I never realized that you can actually hide it altogether.&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.no-cursor&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;cursor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, that doesn&#39;t mean you &lt;em&gt;should&lt;/em&gt;, it just means you &lt;em&gt;can&lt;/em&gt;. Practical uses for this are definitely limited, but things like mouse-based games come to mind.&lt;/p&gt;
&lt;p&gt;What other use cases can you think of for hiding the mouse cursor? If you think of any, &lt;a href=&quot;https://x.com/claviska&quot;&gt;let me know on Twitter.&lt;/a&gt;&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>How to leave a console greeting for your visitors</title>
		<link href="https://www.abeautifulsite.net/posts/how-to-leave-a-console-greeting-for-your-visitors/"/>
		<updated>2014-08-27T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/how-to-leave-a-console-greeting-for-your-visitors/</id>
		<content type="html">&lt;p&gt;Since my audience consists primarily of web developers, I decided to try a little experiment the other day. I added a console greeting to the site for anyone who decides to look under the hood. Here&#39;s how I did it.&lt;/p&gt;
&lt;h2 id=&quot;what-the-heck-is-a-console-greeting%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/how-to-leave-a-console-greeting-for-your-visitors/#what-the-heck-is-a-console-greeting%3F&quot;&gt;What the heck is a console greeting?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Some time ago, I saw a post about a web design agency that advertised a developer job in an HTML comment on their website. The idea was that a developer might be checking out the source and possibly apply for the position. I&#39;m not sure if it worked, but it was definitely a clever idea.&lt;/p&gt;
&lt;p&gt;The other day I was updating a script and thought, &amp;quot;how cool would it be if someone left a fun greeting in the developer console?&amp;quot;&lt;/p&gt;
&lt;p&gt;Lately I&#39;ve been trying to write more about my experience running a bootstrapped SaaS business, which I think can be very valuable to developers. To help promote this new section of the blog, I added the following message that will appear in a visitor&#39;s console should they happen to open it while visiting my site:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/console-greeting.png&quot; alt=&quot;Screenshot of a console greeting&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The greeting invites visitors to check out the &lt;em&gt;Business&lt;/em&gt; section of my blog, and I&#39;ve left my Twitter handle in case they want to get in touch with me. The panther is there as a &amp;quot;wow&amp;quot; effect, which I think will help reception. What&#39;s nice is that in Chrome and Safari, the link is actually clickable!&lt;/p&gt;
&lt;h2 id=&quot;how-to-do-it&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/how-to-leave-a-console-greeting-for-your-visitors/#how-to-do-it&quot;&gt;How to do it&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The idea is simple. When the page loads, leave a message in the developer console. All it takes is a bit of JavaScript:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&#39;&#92;n&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&#39;Hi there, fellow developer! Thanks for visiting.&#92;n&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&#39;If you’re an aspiring bootstrapper, startup-er,&#92;n&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&#39;or business owner, make sure you check out this         (&quot;&#92;`-’-/&quot;).___..--’’&quot;&#92;`-._&#92;n&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&#39;section of the blog for tips and inspiration!            &#92;`6_ 6  )   &#92;`-.  (     ).&#92;`-.__.‘)&#92;n&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&#39;                                                         (_Y_.)’  ._   )  &#92;`._ &#92;`. &#92;`&#92;`-..-’&#92;n&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&#39;http://www.abeautifulsite.net/tags/business            _..&#92;`--’_..-_/  /--’_.’ ,’&#92;n&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&#39;                                                      (il),-’‘  (li),’  ((!.-‘&#92;n&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&#39;I’d love to hear what you think!&#92;n&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&#39;&#92;n&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&#39;— Cory&#92;n&#39;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&#39;s a bit ugly with all the concatenation and newlines, but you get the idea. Of course, if the visitor doesn&#39;t have their console open, they simply won&#39;t see anything. The script itself is benign and only serves as a clever way to reach out to someone who happens to be browsing with the dev console open.&lt;/p&gt;
&lt;p&gt;What do you think of this idea? Silly, fun, annoying, awesome? What other ways can the console be used to charm or impress your tech-savvy visitors? Have you seen any other websites do this?&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Subtle Patterns: hundreds of free backgrounds that tile</title>
		<link href="https://www.abeautifulsite.net/posts/subtle-patterns-hundreds-of-free-backgrounds-that-tile/"/>
		<updated>2014-08-25T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/subtle-patterns-hundreds-of-free-backgrounds-that-tile/</id>
		<content type="html">&lt;p&gt;I&#39;ve been using &lt;a href=&quot;https://www.toptal.com/designers/subtlepatterns/&quot;&gt;Subtle Patterns&lt;/a&gt; for quite some time now. All the patterns are great, and their Photoshop plugin is incredibly useful.&lt;/p&gt;
&lt;p&gt;I can&#39;t remember when it first launched, but I do remember when there was only one or two pages to browse on the site. Now it has over 380 images you can use for free in your own projects. The collection is curated by &lt;a href=&quot;https://twitter.com/atlemo&quot;&gt;Atle Mo&lt;/a&gt;, who does a great job in maintaining subtle, consistent backgrounds out of the tons of images that users submit.&lt;/p&gt;
&lt;p&gt;All of the patterns tile nicely (which you can test by selecting &lt;em&gt;Preview&lt;/em&gt;) and all are available under a Creative Commons license. If you&#39;re a designer with a knack for tessellations, you might be one of the &lt;a href=&quot;https://www.toptal.com/designers/subtlepatterns/submitpattern/&quot;&gt;lucky 3%&lt;/a&gt; whose pattern gets accepted.&lt;/p&gt;
&lt;p&gt;I bought the Photoshop plugin the day it came out, which I highly recommend if you use Photoshop for web design. It&#39;s so much better than tiling the images yourself or going to &lt;em&gt;Edit &amp;gt; Define Pattern&lt;/em&gt; every time you want to try out a new background. It also has a slick logo, which always a good reason to buy something.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/subtle-patterns-plugin.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Seriously, it&#39;s an awesome service, so now&#39;s a good time to add &lt;a href=&quot;https://www.toptal.com/designers/subtlepatterns/&quot;&gt;Subtle Patterns&lt;/a&gt; to your bookmarks if it&#39;s not already there.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Find a name for almost any hex color</title>
		<link href="https://www.abeautifulsite.net/posts/find-a-name-for-almost-any-hex-color/"/>
		<updated>2014-08-22T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/find-a-name-for-almost-any-hex-color/</id>
		<content type="html">&lt;p&gt;Have you ever wondered what color that certain shade of blue is? Or maybe you&#39;ve named your Less/Sass variables something like &lt;em&gt;gray&lt;/em&gt;, &lt;em&gt;light gray&lt;/em&gt;, &lt;em&gt;lighter gray&lt;/em&gt;, etc. Here&#39;s a tool that will give you more reasonable names for all those colors.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://chir.ag/projects/name-that-color/&quot;&gt;Name that Color&lt;/a&gt; lets you enter a hex value (or choose one from the color picker) and gives you a human-readable name for the closest matching shade. There are over 1,500 color names available, ranging from &lt;em&gt;alabaster&lt;/em&gt; to &lt;em&gt;zinnwaldite&lt;/em&gt;. Others are more common, such as &lt;em&gt;brick red&lt;/em&gt;, &lt;em&gt;chocolate&lt;/em&gt;, and &lt;em&gt;slate gray.&lt;/em&gt; Even if you don&#39;t land on a perfect match, the nearest named-color is only a shade or two away.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://chir.ag/projects/name-that-color/&quot;&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/name-that-color.png&quot; alt=&quot;Name that Color&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The author also provided the &lt;a href=&quot;http://chir.ag/projects/ntc/&quot;&gt;JavaScript library&lt;/a&gt; behind it all under a Creative Commons license. It&#39;s really easy to use:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Find the nearest match&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; match &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ntc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;#6195ED&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// The resulting array&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; closest &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; match&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// RGB value of the closest match&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; name    &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; match&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// The color name&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; exact   &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; match&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// True if it&#39;s an exact match&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What will you do with this handy tool?&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Working with HTML5 data attributes</title>
		<link href="https://www.abeautifulsite.net/posts/working-with-html5-data-attributes/"/>
		<updated>2014-08-21T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/working-with-html5-data-attributes/</id>
		<content type="html">&lt;p&gt;Before HTML5, working with arbitrary data sucked. To keep things valid, you had to stuff things into &lt;code&gt;rel&lt;/code&gt; or &lt;code&gt;class&lt;/code&gt; attributes. Some developers even created their own custom attributes. Boy, was it a mess.&lt;/p&gt;
&lt;p&gt;But that all changed with the introduction of HTML5 custom data attributes. Now you can store arbitrary data in an easy, standards-compliant way.&lt;/p&gt;
&lt;h2 id=&quot;how-do-data-attributes-work%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/working-with-html5-data-attributes/#how-do-data-attributes-work%3F&quot;&gt;How do data attributes work?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A data attribute is exactly that: a custom attribute that stores data. They are always prefixed with &lt;code&gt;data-&lt;/code&gt; followed by something descriptive (according to &lt;a href=&quot;http://www.w3.org/html/wg/drafts/html/master/dom.html#custom-data-attribute&quot;&gt;the spec&lt;/a&gt;, only lower case letters and hyphens are allowed). An element can have any number of data attributes you want.&lt;/p&gt;
&lt;p&gt;Here&#39;s an example using a list item to store data for a user:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1234&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-email&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;calvin@example.com&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-age&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;21&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Calvin&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, this data isn&#39;t very useful to a visitor because they can&#39;t actually see it, but it&#39;s wildly useful for building web applications. Imagine a delete button in your app:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-cmd&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;delete&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1234&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Delete&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All the data you need is right there to send to your backend script. No more &lt;code&gt;rel&lt;/code&gt; stuffing or parsing IDs and actions out of other attributes. Data URLs make your life easier.&lt;/p&gt;
&lt;h2 id=&quot;what-can-you-store%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/working-with-html5-data-attributes/#what-can-you-store%3F&quot;&gt;What can you store?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One thing to remember when working with data attributes is that you can&#39;t store objects in them. Well, you can if you serialize them, but we&#39;ll save that for another post.&lt;/p&gt;
&lt;p&gt;For now, just know that you&#39;re pretty much limited to storing strings.&lt;/p&gt;
&lt;h2 id=&quot;reading%2Fwriting-data-attributes-with-javascript&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/working-with-html5-data-attributes/#reading%2Fwriting-data-attributes-with-javascript&quot;&gt;Reading/writing data attributes with JavaScript&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Using the delete button as an example, let&#39;s look at how we can access this data with JavaScript.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Here&#39;s our button&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; button &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;your-button-id&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Get the values&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; cmd &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; button&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;data-cmd&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; button&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;data-id&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Change the values&lt;/span&gt;
button&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;data-cmd&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; yourNewCmd&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
button&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;data-id&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; yourNewId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pretty simple, right? Now you can pass &lt;code&gt;cmd&lt;/code&gt; and &lt;code&gt;id&lt;/code&gt; to your app in an AJAX request or do whatever else you need to do with it.&lt;/p&gt;
&lt;h2 id=&quot;reading%2Fwriting-data-attributes-with-jquery&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/working-with-html5-data-attributes/#reading%2Fwriting-data-attributes-with-jquery&quot;&gt;Reading/writing data attributes with jQuery&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here&#39;s the same thing using jQuery&#39;s &lt;a href=&quot;http://api.jquery.com/attr/&quot;&gt;&lt;code&gt;.attr()&lt;/code&gt;&lt;/a&gt; method:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Get the values&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; cmd &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;#your-button-id&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;data-cmd&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;#your-button-id&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;data-id&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Change the values&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;#your-button-id&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;data-cmd&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; yourNewCmd&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;data-id&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; yourNewId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Don&#39;t get this confused with jQuery&#39;s &lt;a href=&quot;http://api.jquery.com/data/&quot;&gt;&lt;code&gt;.data()&lt;/code&gt;&lt;/a&gt; method. Although there is some overlap in how data attributes and &lt;code&gt;.data()&lt;/code&gt; work, they&#39;re two totally different things. If you&#39;re not familiar with it, just stick with &lt;code&gt;.attr()&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;using-the-dataset-api&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/working-with-html5-data-attributes/#using-the-dataset-api&quot;&gt;Using the dataset API&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;HTML5 actually has an API just for working with this type of data. Alas, &lt;a href=&quot;http://caniuse.com/#feat=dataset&quot;&gt;IE10 and below&lt;/a&gt; don&#39;t fully support it, but it&#39;s still worth mentioning.&lt;/p&gt;
&lt;p&gt;Using the button example again, here&#39;s how to get and set data attributes using the dataset API:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Here&#39;s our button&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; button &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;your-button-id&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Get the values&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; cmd &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; button&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cmd&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; button&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Change the values&lt;/span&gt;
button&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cmd &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; yourNewCmd&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
button&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; yourNewId&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note how there&#39;s no &lt;code&gt;data&lt;/code&gt; prefix or dashes here. Similar to the way CSS properties work in JavaScript, you&#39;ll need to use camel case notation. The dataset API converts each one so you&#39;ll always have &lt;code&gt;data-some-attribute-name&lt;/code&gt; in your HTML and &lt;code&gt;dataset.someAttributeName&lt;/code&gt; in your JavaScript. Magic!&lt;/p&gt;
&lt;h2 id=&quot;things-you-can-do-with-data-attributes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/working-with-html5-data-attributes/#things-you-can-do-with-data-attributes&quot;&gt;Things you can do with data attributes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The examples above are very basic, but you can do so much with custom data attributes. Here are a few examples off the top of my head.&lt;/p&gt;
&lt;h3 id=&quot;filtering&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/working-with-html5-data-attributes/#filtering&quot;&gt;Filtering&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Say you have a list of things and you want to filter them by keyword. Just put the keywords into a data attribute and write a short script to loop through and show/hide them accordingly.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;filter&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ul&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cars&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-models&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;mustang, f150, 500, fusion&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Ford&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-models&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;corvette, silverado, impala, cavalier&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Chevrolet&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    ...
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&#39;s a quick and dirty filter using jQuery:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$(&#39;#filter&#39;).on(&#39;keyup&#39;, function() {
  var keyword = $(this).val().toLowerCase();
  $(&#39;.cars &amp;gt; li&#39;).each(function() {
    $(this).toggle(keyword.length &amp;lt; 1 || $(this).attr(&#39;data-models&#39;).indexOf(keyword) &amp;gt; -1);
  });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;styling&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/working-with-html5-data-attributes/#styling&quot;&gt;Styling&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It&#39;s arguably better to use classes, but you can style things against data attributes too. Here&#39;s how to apply a style if the element has a certain data attribute (regardless of its value). First, the HTML:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;label&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-warning&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now the CSS:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;[data-warning]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; red&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But what if we wanted to style it based on the data attribute&#39;s value? This will work for any &lt;code&gt;data-warning&lt;/code&gt; attribute that contains the word &lt;em&gt;error&lt;/em&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;[data-warning*=error]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; red&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;configuring&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/working-with-html5-data-attributes/#configuring&quot;&gt;Configuring&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://getbootstrap.com/&quot;&gt;Bootstrap&lt;/a&gt; uses data attributes as an HTML alternative to configuring plugins via JavaScript. Here&#39;s an example of a &lt;a href=&quot;http://getbootstrap.com/javascript/#popovers&quot;&gt;popover&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;btn btn-default&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-container&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-toggle&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;popover&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-placement&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;top&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Vivamus sagittis lacus vel augue laoreet rutrum faucibus.&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  Popover on top
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;a-better-way-to-store-data&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/working-with-html5-data-attributes/#a-better-way-to-store-data&quot;&gt;A better way to store data&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Custom data attributes are widely used all over the web. The nice thing is that they work fine in older browsers, and they adhere to web standards moving forward. That means you can start using them today knowing that they won&#39;t stop working tomorrow.&lt;/p&gt;
&lt;p&gt;I&#39;ve shown you a few common ways to use custom data attributes. What other uses can you think of? Have you used them before? Let me know by commenting below!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Is it possible to be an introverted entrepreneur?</title>
		<link href="https://www.abeautifulsite.net/posts/is-it-possible-to-be-an-introverted-entrepreneur/"/>
		<updated>2014-08-21T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/is-it-possible-to-be-an-introverted-entrepreneur/</id>
		<content type="html">&lt;p&gt;&lt;a href=&quot;https://twitter.com/rem/status/502438066355961856&quot;&gt;A tweet by Remy Sharp&lt;/a&gt; sparked my thoughts about being an introvert and starting a company. I don&#39;t hate human beings, but I do tend to keep to myself. How has this impacted my ability to run a successful business?&lt;/p&gt;
&lt;h2 id=&quot;launching-a-product-is-hard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/is-it-possible-to-be-an-introverted-entrepreneur/#launching-a-product-is-hard&quot;&gt;Launching a product is hard&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you don&#39;t have a good network, launching a product is hard. Without an immediate audience to provide feedback and help promote your idea, you&#39;re stuck waiting for users to trickle in. That means it takes longer to know what&#39;s good, what sucks, and what&#39;s missing. The birth of your product is a critical time, so the last thing you want is to have a lot of downtime and lack of feedback during this period.&lt;/p&gt;
&lt;p&gt;When I launched my first SaaS product, that&#39;s exactly what happened. I promoted the service through my blog, fed some cash into AdWords, and waited for it to get recognized. I was expecting users to pour in, but that didn&#39;t happen. It took some time for things to really pick up, and I attribute that to my lack of social interaction.&lt;/p&gt;
&lt;p&gt;Being an introvert, I wasn&#39;t tapped into social media the way many startups are. I didn&#39;t hang out at trendy bars with my tech friends. Working from home, I wasn&#39;t good at meeting people with similar interests. I thought I could let technology do all the marketing for me.&lt;/p&gt;
&lt;p&gt;It seems that, when you keep to yourself, you end up underestimating the need to connect with people. In hindsight, I made a lot of mistakes because of that. Perhaps the best lesson I&#39;ve learned out of all this is that you need people, whether you like it or not.&lt;/p&gt;
&lt;h2 id=&quot;my-product-should-have-failed&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/is-it-possible-to-be-an-introverted-entrepreneur/#my-product-should-have-failed&quot;&gt;My product should have failed&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By most accounts my product should have failed, but I had one thing that saved it. I&#39;m much better at email than I am in person or on the phone. Because of this, I was able to connect with users who asked questions or signed up and build their trust. I had support emails pushed to my phone and would respond at all times of the day. My commitment to fast and friendly support was my saving grace. It kept things going as I learned how to market and grow a SaaS business.&lt;/p&gt;
&lt;p&gt;As it turned out, I wasn&#39;t actually an introvert. I was just better at typing than I was at talking.&lt;/p&gt;
&lt;p&gt;Once I learned to use that to my advantage, everything changed. If I was good at email, why couldn&#39;t I be good on Facebook and Twitter, too? That got me out of my shell so I could engage people better online, which has helped significantly. It also encouraged me to get out there in the real world and do the same thing.&lt;/p&gt;
&lt;h2 id=&quot;networking-is-a-way-of-life&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/is-it-possible-to-be-an-introverted-entrepreneur/#networking-is-a-way-of-life&quot;&gt;Networking is a way of life&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A very successful person once told me that networking is the key to success. &amp;quot;It&#39;s not what you know, it&#39;s who you know.&amp;quot; This is unfortunately true in the world of business. If you think you can be an introvert and still be successful, you&#39;re in for a rough ride. Of course, nothing is impossible, but why make it harder for yourself? People aren&#39;t all that bad.&lt;/p&gt;
&lt;p&gt;If you disagree with that last sentence, perhaps you&#39;ve been hanging out with the wrong crowd. Find like-minded people that share similar interests. Go out of your comfort zone to reach out and meet people that are more like you. This can be difficult if you&#39;re no longer in high school or college, but it&#39;s not impossible.&lt;/p&gt;
&lt;p&gt;That same successful person also told me that networking is a way of life. It&#39;s not something you force yourself to do just once a month at a local meet-up. It happens anywhere and everywhere you go. Instead of avoiding people, smile and act friendly. Offer to help them whenever you can. You never know when or where you&#39;ll spark up a conversation with someone who will change your life.&lt;/p&gt;
&lt;h2 id=&quot;it&#39;s-probably-impossible&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/is-it-possible-to-be-an-introverted-entrepreneur/#it&#39;s-probably-impossible&quot;&gt;It&#39;s probably impossible&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Is it impossible to be an introvert and an entrepreneur? Unless you&#39;re marketing your product directly to cats, I would say your odds of success are unlikely. I wasn&#39;t the most outgoing person and I definitely ran into issues. Fortunately, I was able to realize my aversion to social interaction and work on fixing it.&lt;/p&gt;
&lt;p&gt;That was years ago. Since then, I&#39;ve grown comfortable walking right up to people and introducing myself. I&#39;ve given presentations to small and mid-sized groups of people. I try to be more active both online and in person. I attend local meet-ups, conferences, and other social gatherings a few times a month.&lt;/p&gt;
&lt;p&gt;Although I used to be fine with the idea of being an introvert, I&#39;ve learned that it&#39;s not the best personality to have when you&#39;re trying to run a business. It&#39;s the equivalent of being a lifeguard that doesn&#39;t know how to swim. Sure, you might be able to rescue a few people, but your odds of succeeding will be much lower because you&#39;re lacking a mission critical skill.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>How to use the PHP ternary operator</title>
		<link href="https://www.abeautifulsite.net/posts/how-to-use-the-php-ternary-operator/"/>
		<updated>2014-08-18T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/how-to-use-the-php-ternary-operator/</id>
		<content type="html">&lt;p&gt;When I learned how to use the ternary operator years ago, I fell in love with it. What a cool way to simplify assignments based on a condition. If you&#39;re not sure what the ternary operator is or how it works, you&#39;re missing out on a really cool piece of programming knowledge.&lt;/p&gt;
&lt;p&gt;Let&#39;s start out with an example and I&#39;ll explain how it works below. I&#39;ll use PHP, but the syntax is exactly the same for JavaScript. Let&#39;s say we want to assign one of two values to &lt;code&gt;$x&lt;/code&gt; based on a certain condition. Using a conditional (if/then/else), it would look like this:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$valid&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token variable&quot;&gt;$x&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;yes&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token variable&quot;&gt;$x&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;no&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That should be pretty easy to read. If &lt;code&gt;$valid&lt;/code&gt; is &lt;code&gt;true&lt;/code&gt; set &lt;code&gt;$x&lt;/code&gt; to &lt;em&gt;yes&lt;/em&gt;, otherwise set it to &lt;em&gt;no&lt;/em&gt;. But this example is rather long for such a simple assignment. Let&#39;s do it in one line with ternary logic:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$x&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$valid&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;yes&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;no&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This produces the same result as before, but it&#39;s much shorter. Read it out loud like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If &lt;em&gt;x&lt;/em&gt; is valid set it to &lt;em&gt;yes&lt;/em&gt;; otherwise set it to &lt;em&gt;no&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It&#39;s not that intimidating once you wrap your head around it. You can even nest them if you feel like being dangerous:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$valid&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;$lang&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;french&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token variable&quot;&gt;$x&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$valid&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$lang&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;french&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;oui&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;yes&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$lang&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;french&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;non&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;no&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$x&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// outputs &#39;oui&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Try running this script in your dev environment and playing with the values to better understand how it works.&lt;/p&gt;
&lt;p&gt;I will, however, caution you to not go crazy with these. Overusing and nesting ternary logic can make your code really hard to read. A good rule of thumb is, if you have to re-read it multiple times to understand it, you should probably use a conditional or a switch statement instead.&lt;/p&gt;
&lt;h2 id=&quot;ternary-shorthand&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/how-to-use-the-php-ternary-operator/#ternary-shorthand&quot;&gt;Ternary shorthand&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This trick only works in PHP 5.3+ and can sometimes make your logic even shorter. Consider this:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token variable&quot;&gt;$start&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token variable&quot;&gt;$start&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Granted, you probably wouldn&#39;t do that in your code. You&#39;d probably do something like this instead:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token variable&quot;&gt;$start&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But that&#39;s still three lines of code. Let&#39;s try with the shorthand ternary operator now:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$start&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$start&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Much better. Just remember that this shorthand trick won&#39;t work in JavaScript!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Five things I&#39;ve learned about taking risks</title>
		<link href="https://www.abeautifulsite.net/posts/five-things-ive-learned-about-taking-risks/"/>
		<updated>2014-08-18T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/five-things-ive-learned-about-taking-risks/</id>
		<content type="html">&lt;p&gt;I had a cush job at a university with great benefits, decent pay, and normal hours. Five years ago, I took a risk and gave it all up to start a company. Here are the five most important lessons I&#39;ve learned about risk-taking.&lt;/p&gt;
&lt;h2 id=&quot;1.-there-are-good-risks-and-bad-risks&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/five-things-ive-learned-about-taking-risks/#1.-there-are-good-risks-and-bad-risks&quot;&gt;1. There are good risks and bad risks&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;People that jump into things too quickly tend to achieve unfavorable results. They get excited by the potential and become blind to the consequences. On the other hand, people that wait too long end up missing opportunities due to fear and reluctance. Taking risks can be stressful and dangerous, but it can also change your life.&lt;/p&gt;
&lt;p&gt;I&#39;ve learned that there are good risks and bad risks, but figuring out how to measure them isn&#39;t easy. Even if you write down all the pros and cons, the answer might still be unclear. Perhaps that&#39;s why so many people talk about risks. It&#39;s a complicated subject. &lt;a href=&quot;http://www.amazon.com/s/ref=sr_nr_n_0/188-1398068-9841564?rh=n%3A283155%2Cn%3A4749%2Ck%3Arisk+taking&amp;amp;keywords=risk+taking&amp;amp;ie=UTF8&amp;amp;qid=1408142253&amp;amp;rnid=1000&quot;&gt;Look how many books there are&lt;/a&gt; about it.&lt;/p&gt;
&lt;p&gt;I&#39;d love to say &amp;quot;just go with your gut&amp;quot;, but that hasn&#39;t always worked for me. You have to be smart enough to recognize opportunity while being cautious enough to realize what&#39;s at stake. It&#39;s a lot like gambling, but if you understand the game you&#39;re playing you have a much better shot at coming out ahead.&lt;/p&gt;
&lt;p&gt;Do your research. Run numbers. Consider your best and worst case scenarios. Listen to your gut instinct, but don&#39;t let it trump logic. At the end of the day, there should be a little bit of comfort and a little bit of concern when you decide to take a risk. If either is missing, consider it a red flag.&lt;/p&gt;
&lt;h2 id=&quot;2.-the-odds-are-better-than-you-think&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/five-things-ive-learned-about-taking-risks/#2.-the-odds-are-better-than-you-think&quot;&gt;2. The odds are better than you think&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When I quit my job, I already had something going on the side to help cover my expenses while the business ramped up. I planned it out so if things didn&#39;t go the way I expected, I&#39;d have something to fall back on. I would never recommend risking everything without having some kind of safety net. That&#39;s a crapshoot and, if you&#39;ve ever been to Vegas, you should know there&#39;s a good chance that it won&#39;t work out in your favor.&lt;/p&gt;
&lt;p&gt;The key to taking risks is to take smart ones, which requires a solid understanding of how things work. Of course, there are always uncertainties — that&#39;s why it&#39;s called a &amp;quot;risk&amp;quot;—but you can stack the deck in your favor by being knowledgeable, timely, and persistent.&lt;/p&gt;
&lt;p&gt;When I launched my first product, it was second to market for the type of service it was. That means it wasn&#39;t featured on many tech blogs and it didn&#39;t get the kind of coverage or hype that its competitor did. Rather than give up, I decided to roll out some key features quickly and promote the service as much as possible anyway. Marketing wasn&#39;t my thing back then (it still isn&#39;t), but I studied up and kept at it. My persistence ultimately paid off. In November, my service will see its sixth profitable year of operation!&lt;/p&gt;
&lt;h2 id=&quot;3.-don&#39;t-listen-to-people&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/five-things-ive-learned-about-taking-risks/#3.-don&#39;t-listen-to-people&quot;&gt;3. Don&#39;t listen to people&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I talked to a lot of people before quitting my job. I spoke with my parents, my friends, and even some coworkers about it. Their advice was mixed. Some of them told me to go for it and start my own thing, but most of them told me it was a bad idea. While the former fueled my adrenaline, the latter made me very anxious. I wasn&#39;t sure how to handle that type of feedback. I mean, these people were all smart and well-educated and I thought my plan was solid. So who should I listen to?&lt;/p&gt;
&lt;p&gt;The answer is none of them. While getting advice from smart and experienced people is perfectly fine, you shouldn&#39;t let others decide what risks you take in life. No matter how close you are to someone, they&#39;ll never fully understand your situation like you do. They don&#39;t know your financial status, how motivated you are, or how successful you&#39;ll be. They can only tell you what they would do (or what they wouldn&#39;t do) if they were in your shoes.&lt;/p&gt;
&lt;p&gt;Now that could be valuable advice if you&#39;re talking to a successful entrepreneur, but how many successful entrepreneurs do you personally know? I didn&#39;t know any, so I had to go with my gut. I listened to everyone&#39;s advice, thought it through, and decided to take the risk. Six years later, I have no regrets.&lt;/p&gt;
&lt;h2 id=&quot;4.-the-fun-is-in-the-journey%2C-not-the-destination&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/five-things-ive-learned-about-taking-risks/#4.-the-fun-is-in-the-journey%2C-not-the-destination&quot;&gt;4. The fun is in the journey, not the destination&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Oh, the many nights I&#39;ve spent developing things, writing blog posts, fixing bugs, repairing databases, responding to support tickets, and playing around with new technologies. I&#39;m fortunate enough to do what I love for a living, and I never take that for granted. Even when things get stressful, I never wish I were doing something else.&lt;/p&gt;
&lt;p&gt;To keep things moving forward, I have numerous goals: growth, new products, hiring employees, an office building downtown...but there isn&#39;t any finish line, nor should there be. With each goal comes new risks, and with each risk my journey gets more exciting. There&#39;s no point at which you&#39;ll sit down and say, &amp;quot;there, I&#39;ve done it. It&#39;s all over now.&amp;quot; Instead, you&#39;ll ask yourself, &amp;quot;what can I do next?&amp;quot;&lt;/p&gt;
&lt;p&gt;Even if you nailed that goal of $1M in revenue, you don&#39;t stop working and that&#39;s it. There&#39;s always something else you can turn your attention to. When you succeed, remember what works. When you fail, remember what doesn&#39;t. Use that to your advantage and you&#39;ll make better decisions in the future. If starting a business is like a road trip, then knowledge is your fuel. Don&#39;t worry so much about the destination — just enjoy the ride and keep putting gas in your tank.&lt;/p&gt;
&lt;h2 id=&quot;5.-know-when-to-call-it-quits&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/five-things-ive-learned-about-taking-risks/#5.-know-when-to-call-it-quits&quot;&gt;5. Know when to call it quits&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Sometimes, it just isn&#39;t meant to be. Even if you&#39;ve done something once, doing it again can be a completely different experience. I&#39;ve played around with many ideas, developed prototypes, bought domain names, and most of them are just memories now. You have to know when to call it quits before it drags you down and burns you out.&lt;/p&gt;
&lt;p&gt;There was a project I really wanted to develop a few years ago. I had a logo designed, created a website for it, and even had a partially working prototype until I hit a major road block. At the time, I had to make a decision. I already wasted months of resources working on a project that I didn&#39;t even know was viable, and another project was already overdue for a major update. Should I spend the next six months trying to get this thing to work while the other (more successful) project suffered? No way. It was time to call it quits.&lt;/p&gt;
&lt;p&gt;When you have a lot of time invested into a project — especially your project — it can be very hard to let go. Maybe it&#39;s pride or simply the fear of failure. Maybe a bit of both? In the end, I knew I had to give up on it and move on.&lt;/p&gt;
&lt;p&gt;The crazy thing is that once I killed the project, I felt so much better. It was a huge weight off my shoulders. I was able to focus on the more successful service and ultimately launched a new version that caused its user base to triple in one year!&lt;/p&gt;
&lt;h2 id=&quot;a-tip-to-take-home&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/five-things-ive-learned-about-taking-risks/#a-tip-to-take-home&quot;&gt;A tip to take home&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Risk-taking shouldn&#39;t be something that scares you — it should be something that excites you. Look for opportunities, but be cautious and plan when to make your move. If you asked me for just one piece of advice I&#39;ve learned about taking risks, it would be this:&lt;/p&gt;
&lt;p&gt;Waiting too long can be just as bad as not waiting long enough!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Using the classList API</title>
		<link href="https://www.abeautifulsite.net/posts/using-the-classlist-api/"/>
		<updated>2014-08-15T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/using-the-classlist-api/</id>
		<content type="html">&lt;p&gt;jQuery makes it easy to add, remove, and toggle classes on various elements. It&#39;s too bad this stuff wasn&#39;t built into JavaScript. But wait — it is now!&lt;/p&gt;
&lt;p&gt;What your looking for didn&#39;t exist until IE10, but it&#39;s been in Firefox, Chrome, Safari, and Opera for some time now. It&#39;s called the &lt;code&gt;classList&lt;/code&gt; API, and it makes working with classes a breeze, even without a library.&lt;/p&gt;
&lt;p&gt;For these examples, assume that &lt;code&gt;el&lt;/code&gt; is a reference to an element on your page.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Adding a class&lt;/span&gt;
el&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;classList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;your-class-name&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Removing a class&lt;/span&gt;
el&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;classList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;some-class-name&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Toggling a class on/off&lt;/span&gt;
el&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;classList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toggle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;some-class-name&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Checking for a class&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;el&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;classList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;some-class-name&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// has the class&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// doesn&#39;t have the class&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is just as easy as any library out there, and you can use it today if you&#39;re not worried about IE9 and below. (Actually, you can still use it with &lt;a href=&quot;https://github.com/eligrey/classList.js&quot;&gt;a shim&lt;/a&gt;.)&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>TinyPNG: A better way to compress PNG images</title>
		<link href="https://www.abeautifulsite.net/posts/tinypng-a-better-way-to-compress-png-images/"/>
		<updated>2014-08-15T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/tinypng-a-better-way-to-compress-png-images/</id>
		<content type="html">&lt;p&gt;By now, you know that optimizing images and other resources can reduce bandwidth and help your website load faster. Perhaps you&#39;ve even used a tool like &lt;a href=&quot;http://pmt.sourceforge.net/pngcrush/&quot;&gt;Pngcrush&lt;/a&gt; before to make your images smaller. Now, there&#39;s an even better solution.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://tinypng.com/&quot;&gt;TinyPNG&lt;/a&gt; uses &amp;quot;smart lossy compression techniques&amp;quot; to make your images smaller. &lt;em&gt;But wait, isn&#39;t PNG a lossless format?&lt;/em&gt; Yes, and that&#39;s the beauty of TinyPNG:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;By selectively decreasing the number of colors in the image, fewer bytes are required to store the data. The effect is nearly invisible but it makes a very large difference in file size!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To accomplish this, TinyPNG uses a &lt;a href=&quot;http://en.wikipedia.org/wiki/Quantization_(image_processing)&quot;&gt;quantization&lt;/a&gt; algorithm to reduce the number of colors in a way that&#39;s virtually undetectable to the naked eye. This is the same technique that &lt;a href=&quot;https://www.abeautifulsite.net/how-to-get-the-dominant-colors-of-an-image-with-javascript&quot;&gt;Color Thief&lt;/a&gt; uses to generate color palettes from photos.&lt;/p&gt;
&lt;p&gt;Here&#39;s how it works in more detail:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When you upload a PNG (Portable Network Graphics) file, similar colors in your image are combined. This technique is called “quantization”. Because the number of colors is reduced, 24-bit PNG files can be converted to much smaller 8-bit indexed color images. All unnecessary metadata is stripped too. The result: tiny PNG files with 100% support for transparency.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And here&#39;s a before/after comparison:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.abeautifulsite.net/images/tinypng-example.png&quot;&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/tinypng-example.png&quot; alt=&quot;TinyPNG example&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It&#39;s visually the same, but 74% smaller. Of course, this percentage will vary for each image. I&#39;ve been using TinyPNG quite a bit lately and haven&#39;t found a single instance where the results were unacceptable.&lt;/p&gt;
&lt;p&gt;While using their website is free, there are some paid options for TinyPNG. Instead of dropping your images onto their page, you can get the &lt;a href=&quot;https://tinypng.com/photoshop&quot;&gt;TinyPNG Photoshop plugin&lt;/a&gt; for $40. There&#39;s also a &lt;a href=&quot;https://tinypng.com/developers&quot;&gt;developer API&lt;/a&gt; with both free and paid plans. (If you want a Bash script that uses their API, &lt;a href=&quot;https://github.com/RanyAlbegWein/Tinypng&quot;&gt;here&#39;s one&lt;/a&gt; by &lt;a href=&quot;https://twitter.com/ranyalbegwein&quot;&gt;@RanyAlbegWein&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;What other techniques do you use to make images smaller? Share them with me below!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>What is my browser? This tool will tell you</title>
		<link href="https://www.abeautifulsite.net/posts/what-is-my-browser-this-tool-will-tell-you/"/>
		<updated>2014-08-14T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/what-is-my-browser-this-tool-will-tell-you/</id>
		<content type="html">&lt;p&gt;Last week I wrote about &lt;a href=&quot;https://www.abeautifulsite.net/posts/how-to-get-faster-and-better-help-from-support&quot;&gt;how to get faster and better help from support&lt;/a&gt;. One of my suggestions was to tell them what browser, OS, etc. you&#39;re using. Here&#39;s a free tool that will make that so much easier.&lt;/p&gt;
&lt;p&gt;As soon as you visit &lt;a href=&quot;https://aboutmybrowser.com/&quot;&gt;About My Browser&lt;/a&gt;, it will show you what browser and operating system you&#39;re using. Scroll down a bit and you&#39;ll see more details including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Whether or not JavaScript is enabled&lt;/li&gt;
&lt;li&gt;Whether or not the browser is accepting cookies&lt;/li&gt;
&lt;li&gt;Your screen resolution&lt;/li&gt;
&lt;li&gt;Your browser&#39;s dimensions&lt;/li&gt;
&lt;li&gt;Whether or not Flash is installed&lt;/li&gt;
&lt;li&gt;Whether or not Java is installed&lt;/li&gt;
&lt;li&gt;Your user agent string&lt;/li&gt;
&lt;li&gt;Your language preference&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The site also gives you a link to copy and paste for a support person or friend. That makes it the perfect tool to hand off to your grandmother who can&#39;t get Gmail to load or that annoying guy in the neighborhood who thinks you&#39;re tech support because you work on a computer.&lt;/p&gt;
&lt;p&gt;It&#39;s nothing that a developer would need, but it&#39;s so much easier to say &amp;quot;go here and send me the link&amp;quot; than trying to ask someone who isn&#39;t comfortable with computers all those questions.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Smaller volume increments in macOS</title>
		<link href="https://www.abeautifulsite.net/posts/smaller-volume-increments-in-os-x/"/>
		<updated>2014-08-13T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/smaller-volume-increments-in-os-x/</id>
		<content type="html">&lt;p&gt;Ever wish you turn the volume up or down just a tiny bit more on your Mac? Well, you can.&lt;/p&gt;
&lt;p&gt;You already know you can increase and decrease your Mac&#39;s volume with the keyboard, but sometimes the intervals are a bit too much. I usually end up adjusting my external speakers just to get that perfect volume. But that&#39;s silly. There&#39;s a better way to fine-tune your volume without leaving the keyboard.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/volume-buttons.jpg&quot; alt=&quot;Photo of a macOS keyboard&#39;s volume buttons&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Simply pressing &lt;kbd&gt;option&lt;/kbd&gt; + &lt;kbd&gt;shift&lt;/kbd&gt; + &lt;kbd&gt;volume up/down&lt;/kbd&gt; will result in quarter intervals, which means you can achieve that perfect volume without having to do secondary adjustments.&lt;/p&gt;
&lt;p&gt;What other hidden features of OS X have you come across? Give me something post-worthy and I&#39;ll write about it and credit you in the article.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Link to a specific page in a PDF file</title>
		<link href="https://www.abeautifulsite.net/posts/link-to-a-specific-page-in-a-pdf-file/"/>
		<updated>2014-08-13T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/link-to-a-specific-page-in-a-pdf-file/</id>
		<content type="html">&lt;p&gt;Both Chrome and Firefox render PDF files in the browser, making them easier for users to view. Today I wanted to send someone a link to a certain page in a PDF user&#39;s manual. Here&#39;s how I did it.&lt;/p&gt;
&lt;p&gt;In HTML, you can link to a specific part of the page this using anchors. For example:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- page.html --&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;anchor-name&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Deep Linking Rocks!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- another-page.html --&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;page.html#anchor-name&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Go to it!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you click the link, your browser will take you to the correct location in &lt;code&gt;page.html&lt;/code&gt;, no matter how far down it is.&lt;/p&gt;
&lt;p&gt;But how do you do that with a PDF file? Well, we don&#39;t have access to any IDs so the best we can do is pick a page and link to that instead. Try this:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;document.pdf#page=10&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;http://helpx.adobe.com/acrobat/kb/link-html-pdf-page-acrobat.html&quot;&gt;Per Adobe&lt;/a&gt;, this will link the user to page 10 of &lt;code&gt;document.pdf&lt;/code&gt; in Chrome and Firefox. Note that we&#39;re using a hash instead of a question mark — it&#39;s not actually query string even though it looks a lot like one.&lt;/p&gt;
&lt;p&gt;Alas, not all browsers open PDFs, so it&#39;s best to tell users which page they should look for in case they&#39;re using an unsupportive browser.&lt;/p&gt;
&lt;p&gt;As of this writing, Chrome and Firefox both handle this beautifully. Although Safari opens PDFs, it doesn&#39;t seem to acknowledge the hash. Of course, this will also work if the user has the Adobe Reader plugin installed.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Lessons from my 20s: a presentation by Ryan Allis</title>
		<link href="https://www.abeautifulsite.net/posts/lessons-from-my-20s-a-presentation-by-ryan-allis/"/>
		<updated>2014-08-12T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/lessons-from-my-20s-a-presentation-by-ryan-allis/</id>
		<content type="html">&lt;p&gt;Author and entrepreneur &lt;a href=&quot;https://twitter.com/ryanallis&quot;&gt;Ryan Allis&lt;/a&gt; shares 1,264 slides about life, entrepreneurship, and the world.&lt;/p&gt;
&lt;p&gt;We all have goals, but sometimes they seem hard to reach. Really hard. Life happens and things get tough, but don&#39;t let it get you down. It&#39;s not impossible. It just means you&#39;ll have to work a little harder smarter.&lt;/p&gt;
&lt;p&gt;If you&#39;re like me, you&#39;re driven by aspiration, but it can be easy to get lost on the road to success. Sometimes, simply writing down your goals can make them that much more obtainable. It may sound silly, but it&#39;s been repeated by too many successful people to ignore, and Ryan Allis is one of them.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The first ever goal I wrote down at age 16 was &amp;quot;build a company to $1M in sales by 21. I missed this goal by 18 days.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;http://hive.org/20s/&quot;&gt;In this monster presentation&lt;/a&gt;, Ryan shares many experiences and provides great inspiration for anyone with an interest in running a successful business.&lt;/p&gt;
&lt;p&gt;It&#39;s a long read and lots of scrolling, so make sure you save it for later if you don&#39;t have the time to absorb it all today.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>How to get the dominant colors of an image with Color Thief</title>
		<link href="https://www.abeautifulsite.net/posts/how-to-get-the-dominant-colors-of-an-image-with-color-thief/"/>
		<updated>2014-08-12T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/how-to-get-the-dominant-colors-of-an-image-with-color-thief/</id>
		<content type="html">&lt;p&gt;You know how &lt;a href=&quot;https://dribbble.com/&quot;&gt;Dribbble&lt;/a&gt; shows a color palette for each shot users upload? They always look perfect right? Here&#39;s a tool that can give you the same quality results using pure JavaScript.&lt;/p&gt;
&lt;p&gt;I played with &lt;a href=&quot;http://lokeshdhakar.com/projects/color-thief/&quot;&gt;Color Thief&lt;/a&gt; a few months ago but surprisingly never posted about it. For me, something that&#39;s easy to use and has consistently great results is pure gold. Here&#39;s how it works.&lt;/p&gt;
&lt;h2 id=&quot;getting-the-dominant-color-of-an-image&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/how-to-get-the-dominant-colors-of-an-image-with-color-thief/#getting-the-dominant-color-of-an-image&quot;&gt;Getting the dominant color of an image&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; colorThief &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ColorThief&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
colorThief&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getColor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sourceImage&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// { r: num, g: num, b: num }&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;generating-a-color-palette-from-an-image&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/how-to-get-the-dominant-colors-of-an-image-with-color-thief/#generating-a-color-palette-from-an-image&quot;&gt;Generating a color palette from an image&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; colorThief &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ColorThief&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
colorThief&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getPalette&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sourceImage&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// [[num, num, num], [num, num, num], ...]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Learn more about &lt;a href=&quot;http://lokeshdhakar.com/projects/color-thief/&quot;&gt;how Color Thief works&lt;/a&gt; and try it out with your own photo. The project was created by &lt;a href=&quot;https://twitter.com/lokesh&quot;&gt;Lokesh Dhakar&lt;/a&gt; and licensed under the MIT license.&lt;/p&gt;
&lt;h2 id=&quot;what-about-a-php-version%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/how-to-get-the-dominant-colors-of-an-image-with-color-thief/#what-about-a-php-version%3F&quot;&gt;What about a PHP version?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It&#39;s amazing that JavaScript can do all these great things, but if you&#39;re running PHP on the backend then you&#39;re out of luck. In that case, there&#39;s a &lt;a href=&quot;https://github.com/ksubileau/color-thief-php&quot;&gt;PHP port of Color Thief&lt;/a&gt; that you can use for similar results.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>PlayCanvas: an easy, open source WebGL game engine</title>
		<link href="https://www.abeautifulsite.net/posts/playcanvas-an-easy-open-source-webgl-game-engine/"/>
		<updated>2014-08-11T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/playcanvas-an-easy-open-source-webgl-game-engine/</id>
		<content type="html">&lt;p&gt;Last week I wrote about &lt;a href=&quot;http://www.abeautifulsite.net/faster-javascript-animations-with-velocityjs/&quot;&gt;faster JavaScript animations&lt;/a&gt; using VelocityJS. As if that wasn&#39;t impressive enough, today I&#39;m giving you a dose of HTML5 and WebGL greatness.&lt;/p&gt;
&lt;p&gt;The project is called &lt;a href=&quot;https://playcanvas.com/&quot;&gt;PlayCanvas&lt;/a&gt;, and it dubs itself an open source game engine that brings fun to the web.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;PlayCanvas is the world’s easiest to use WebGL Game Engine. It’s free, it’s open source and it’s backed by amazing developer tools.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It also boasts partnerships with Mozilla, Activision, and ARM. How&#39;s that for momentum?&lt;/p&gt;
&lt;p&gt;So what&#39;s the big deal? Here&#39;s yet another great example of where the web and HTML is going. What started as a simple markup language has evolved into a platform for just about anything you can imagine. Take &lt;a href=&quot;http://apps.playcanvas.com/playcanvas/swooop/swooop&quot;&gt;Swooop&lt;/a&gt; for example, a game built with PlayCanvas whose graphics and gameplay had me convinced I was playing a Nintendo Wii.&lt;/p&gt;
&lt;p&gt;The game isn&#39;t elaborate — it was made to demonstrate what you can do with PlayCanvas, but it&#39;s stunning nevertheless. You navigate a biplane collecting jewels, stars, and fuel while avoiding clouds and other hazards. The plane circles a three dimensional island full of trees, houses, waterfalls, and rocks. In the distances there&#39;s even a windmill and a hot air balloon floating around. Here&#39;s an actual screenshot I took while playing:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/swooop-screenshot.jpg&quot; alt=&quot;Swooop screenshot&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Want to try it yourself? You can &lt;a href=&quot;https://playcanv.as/p/JtL2iqIH/&quot;&gt;play Swooop right now&lt;/a&gt; or explore some of the other &lt;a href=&quot;https://playcanvas.com/explore&quot;&gt;user-contributed games&lt;/a&gt;. Of course, many of these are unpolished games with simple objectives, so don&#39;t expect Xbox quality here. Think of it as a proof-of-concept.&lt;/p&gt;
&lt;p&gt;Cool, right? Here&#39;s one last gem for you: &lt;a href=&quot;https://playcanv.as/p/NIbWnGY4/&quot;&gt;Lego Gangnam Style&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You may laugh, but pretty soon we&#39;ll be seeing entire movies in HTML/WebGL — we might even be able to make our own.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>box-sizing: border-box explained</title>
		<link href="https://www.abeautifulsite.net/posts/box-sizing-border-box-explained/"/>
		<updated>2014-08-08T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/box-sizing-border-box-explained/</id>
		<content type="html">&lt;p&gt;It&#39;s been over two years since Paul Irish &lt;a href=&quot;http://www.paulirish.com/2012/box-sizing-border-box-ftw/&quot;&gt;famously posted&lt;/a&gt; the box-sizing trick that would bring us back to the days of early Internet Explorer.&lt;/p&gt;
&lt;h2 id=&quot;the-good-ol&#39;-days&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/box-sizing-border-box-explained/#the-good-ol&#39;-days&quot;&gt;The good ol&#39; days&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You might remember how Internet Explorer 6 (quirks mode) and below did that whole &lt;a href=&quot;http://en.wikipedia.org/wiki/Internet_Explorer_box_model_bug&quot;&gt;box model thing&lt;/a&gt; wrong. If not, here&#39;s a refresher.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.abeautifulsite.net/images/box-model-comparison.png&quot;&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/box-model-comparison.png&quot; alt=&quot;A comparison of the W3C box model to that of old IE&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You might even remember what a pain it was to develop with. We&#39;re not talking about the days of &lt;a href=&quot;http://www.sitepoint.com/web-foundations/internet-explorer-conditional-comments/&quot;&gt;conditional comments&lt;/a&gt;, we&#39;re talking about the days of horrible CSS hacks littering stylesheets. You know, like this one:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &#92;&lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 140px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    w&#92;&lt;span class=&quot;token property&quot;&gt;idth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This hack tricked older versions of Internet Explorer in such a way that the &lt;code&gt;div&lt;/code&gt; would be the same width in IE and W3C-compliant browsers. (I don&#39;t think I need to go into detail about why this was a bad idea.)&lt;/p&gt;
&lt;p&gt;The funny thing is, we&#39;ve more or less come full circle to the very model we were fighting against. You see, the &lt;code&gt;border-box&lt;/code&gt; trick actually brings us back to the way old IE worked. And it&#39;s glorious. There&#39;s even &lt;a href=&quot;http://css-tricks.com/international-box-sizing-awareness-day/&quot;&gt;a special day&lt;/a&gt; for it.&lt;/p&gt;
&lt;h2 id=&quot;how-it-works&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/box-sizing-border-box-explained/#how-it-works&quot;&gt;How it works&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;border-box&lt;/code&gt; trick effectively changes the way dimensions are measured for every element so it includes borders and padding. Here&#39;s the code, for reference:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;*,
html&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;box-sizing&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; border-box&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;*, *:before, *:after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;box-sizing&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; inherit&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Think of it as a box model reset that will make you enjoy writing CSS. It&#39;s a tried and tested method that works all the way back to IE8, and is used in popular frameworks such as &lt;a href=&quot;http://getbootstrap.com/&quot;&gt;Bootstrap&lt;/a&gt;. There are no performance issues — it&#39;s like a little piece of magic on your webpage.&lt;/p&gt;
&lt;h2 id=&quot;but-some-of-my-plugins-look-funny-now&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/box-sizing-border-box-explained/#but-some-of-my-plugins-look-funny-now&quot;&gt;But some of my plugins look funny now&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I&#39;ve noticed this a few times before. If you&#39;re using a third party plugin whose styles rely on the &lt;code&gt;content-box&lt;/code&gt; model, things might look a bit strange. To fix this, you can create an override class or apply the following styles directly to a parent element of the plugin:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.content-box,
.content-box *&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;box-sizing&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; content-box&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;content-box&quot;&gt;
  &lt;!-- plugin HTML here --&gt;
&lt;/div&gt;
&lt;p&gt;This resets the container and everything inside to the default &lt;code&gt;box-sizing&lt;/code&gt; model, so third-party plugins will render correctly.&lt;/p&gt;
&lt;h2 id=&quot;pick-your-box-model&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/box-sizing-border-box-explained/#pick-your-box-model&quot;&gt;Pick your box model&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The two most common values for &lt;code&gt;box-sizing&lt;/code&gt; are &lt;code&gt;border-box&lt;/code&gt; and &lt;code&gt;content-box&lt;/code&gt;, but another has been introduced more recently. As it&#39;s name implies, &lt;code&gt;padding-box&lt;/code&gt; measures the element&#39;s width, height, and padding but not its border. (Support for the new property &lt;a href=&quot;http://caniuse.com/css3-boxsizing&quot;&gt;isn&#39;t great yet&lt;/a&gt;, so avoid using it for anything serious.)&lt;/p&gt;
&lt;p&gt;To better understand each property, here&#39;s a diagram for reference.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.abeautifulsite.net/images/box-sizing-comparison.png&quot;&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/box-sizing-comparison.png&quot; alt=&quot;A diagram showing the three values for box-sizing: content-box, border-box, and padding-box&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Oh, and before you ask: no, &lt;a href=&quot;http://stackoverflow.com/questions/10808413/css3-box-sizing-margin-box-why-not&quot;&gt;there&#39;s no margin-box&lt;/a&gt;.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Give your JPEGs alpha channels</title>
		<link href="https://www.abeautifulsite.net/posts/give-your-jpegs-alpha-channels/"/>
		<updated>2014-08-07T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/give-your-jpegs-alpha-channels/</id>
		<content type="html">&lt;p&gt;If you need alpha transparency on the web, 24-bit PNGs are usually your best bet. The only problem is that PNGs are lossless and can grow in file size very quickly — much larger than your average JPEG. So what if there was a way for JPEGs to support alpha channels?&lt;/p&gt;
&lt;p&gt;I discovered this trick on &lt;a href=&quot;http://w3.eleqtriq.com/2014/08/applying-alpha-channels-to-jpgs/&quot;&gt;eleqtriq&lt;/a&gt;. The author demonstrates how you can embed a JPEG into an SVG and, with the clever use of a mask, simulate a JPEG with alpha transparency. Since &lt;a href=&quot;http://caniuse.com/svg&quot;&gt;browser support for SVG&lt;/a&gt; is pretty good, there&#39;s nothing stopping you from using this method right now.&lt;/p&gt;
&lt;p&gt;Cool trick, right? Check out &lt;a href=&quot;http://w3.eleqtriq.com/2014/08/applying-alpha-channels-to-jpgs/&quot;&gt;Dirk Weber&#39;s blog&lt;/a&gt; to see exactly how it&#39;s done.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>How to get faster and better help from support</title>
		<link href="https://www.abeautifulsite.net/posts/how-to-get-faster-and-better-help-from-support/"/>
		<updated>2014-08-05T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/how-to-get-faster-and-better-help-from-support/</id>
		<content type="html">&lt;p&gt;It&#39;s tempting to take out your frustrations on the support person answering your email, but don&#39;t send out a message raging about their incompetence. Don&#39;t tell them how their product sucks or doesn&#39;t work the way you expect it to. Don&#39;t TYPE IN ALL CAPS to make sure they understand that you&#39;re frustrated. It won&#39;t get you faster help — it just makes you look like an asshole.&lt;br /&gt;
I&#39;m sure you&#39;ve had your fair share of horrible customer experiences. It happens, but generally speaking, support teams want to help you resolve whatever issue you&#39;re having so you can continue using their product — and they want to do it as quickly as possible.&lt;/p&gt;
&lt;p&gt;Of course, support isn&#39;t an easy job. I&#39;ve done my fair share in the past, and I still help out my own customers to this day. Let me just be clear about one thing: nobody contacts support because everything is fine.&lt;/p&gt;
&lt;p&gt;Here are some tips you can use to better your odds of getting a resolution on your first interaction with support.&lt;/p&gt;
&lt;h2 id=&quot;explain-the-problem-clearly&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/how-to-get-faster-and-better-help-from-support/#explain-the-problem-clearly&quot;&gt;Explain the problem clearly&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;What&#39;s obvious to you may not be obvious to the person reading your support ticket. Tell them exactly what&#39;s going on. Re-read what you wrote before sending it in and ask yourself if the following questions would make sense to another person:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What were you trying to do?&lt;/li&gt;
&lt;li&gt;How did you try to do it?&lt;/li&gt;
&lt;li&gt;What did you expect to happen?&lt;/li&gt;
&lt;li&gt;What actually happened?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In most cases, this would be enough information for me to resolve a support ticket. Don&#39;t have tunnel vision when you submit your request. The person on the other end may not know that you were in a certain screen or trying to do a certain task. A clear, concise explanation will alleviate questions that are otherwise obvious to you and can result in a faster resolution.&lt;/p&gt;
&lt;h2 id=&quot;provide-step-by-step-instructions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/how-to-get-faster-and-better-help-from-support/#provide-step-by-step-instructions&quot;&gt;Provide step-by-step instructions&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When applicable, provide a bulleted list of the steps you took to produce the error or problem. Unless they have a screen-sharing app, support has no way to see what you&#39;re seeing. Tell them what you click, type, or do in a simple list:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the &amp;quot;User&amp;quot; tab&lt;/li&gt;
&lt;li&gt;Select the user named &amp;quot;Bob&amp;quot;&lt;/li&gt;
&lt;li&gt;Click the dropdown under &amp;quot;User Options&amp;quot;&lt;/li&gt;
&lt;li&gt;Select &amp;quot;Delete User&amp;quot;&lt;/li&gt;
&lt;li&gt;An error occurs stating that the user cannot be deleted&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Don&#39;t say something like, &amp;quot;I tried to delete Bob but couldn&#39;t.&amp;quot; There could be many ways to delete a user and the way you&#39;re doing it could be broken — or you could be doing it wrong. Supports needs to know how you&#39;re doing things to replicate and fix whatever the issue is.&lt;/p&gt;
&lt;h2 id=&quot;act-like-a-decent-person&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/how-to-get-faster-and-better-help-from-support/#act-like-a-decent-person&quot;&gt;Act like a decent person&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It should go without saying, but some people still think that hiding behind their monitor and acting like a pretentious asshole is a great way to get help from support. Nothing personal, but the individual you&#39;re trying to get help from doesn&#39;t care if you&#39;re a CEO, a doctor, or the Pope. You&#39;re just a number, and reiterating how important you think you are doesn&#39;t do anything to get a faster resolution. Neither does sarcasm, name calling, or profanity.&lt;/p&gt;
&lt;p&gt;If you want to have a better support experience, just act like a decent human being. Throw a smiley in there to relieve the tension a bit. I guarantee you&#39;ll have a better shot at getting help if you don&#39;t act like a jerk. (Tip: I almost always pick the &amp;quot;nice&amp;quot; tickets before the &amp;quot;mean&amp;quot; ones and I pay more attention when those names come up again in the future.)&lt;/p&gt;
&lt;h2 id=&quot;be-responsive&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/how-to-get-faster-and-better-help-from-support/#be-responsive&quot;&gt;Be responsive&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is absolutely critical if the support team requires additional information or clarification from you. Make yourself available to answer any questions and aid them in resolving the problem. I&#39;ve seen tickets sit open for weeks because the person who submitted it went on holiday or &amp;quot;didn&#39;t have time&amp;quot; to respond.&lt;/p&gt;
&lt;p&gt;Once your support ticket is in progress, you&#39;ll almost always see faster response times than when you submit a new ticket. Take advantage of it and respond as quickly as possible. The sooner you get back to them, the sooner they can get back to you.&lt;/p&gt;
&lt;h2 id=&quot;talk-about-your-technology&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/how-to-get-faster-and-better-help-from-support/#talk-about-your-technology&quot;&gt;Talk about your technology&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;re having a problem with software or a web app, tell the support team what operating system and version you&#39;re running. When applicable, do the same for your web browser. You&#39;d be surprised how many times simply knowing this would have let me close out tickets on the first interaction. Many web apps include this information in their error reporting or ticketing systems — but it still doesn&#39;t hurt to provide it.&lt;/p&gt;
&lt;p&gt;If you don&#39;t know what operating system or browser you&#39;re using, you can find out by &lt;a href=&quot;https://www.whatismybrowser.com/&quot;&gt;going here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&#39;re submitting an issue about a web app, keep in mind that browser plugins and add-ons can cause mysterious things to happen. I&#39;ve seen all sorts of seemingly unrelated things happen as a result of third-party plugins. Try disabling them before submitting a support ticket, or at least let the support person know which ones you have installed in case there&#39;s a known issue.&lt;/p&gt;
&lt;h2 id=&quot;don&#39;t-paste-in-huge-amounts-of-text&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/how-to-get-faster-and-better-help-from-support/#don&#39;t-paste-in-huge-amounts-of-text&quot;&gt;Don&#39;t paste in huge amounts of text&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is especially true if you&#39;re a developer. Don&#39;t paste in a megabyte of code or text to &amp;quot;show&amp;quot; support. It just makes the ticket harder to read. I get a certain tingling in my hand when I open a ticket that does this and it makes me want to skip forward to the next one. Please, for the love of everything sacred, use a service like &lt;a href=&quot;http://pastebin.com/&quot;&gt;PasteBin&lt;/a&gt;. If you don&#39;t want the information to be public, create a secure link using &lt;a href=&quot;http://www.dropbox.com/&quot;&gt;Dropbox&lt;/a&gt; or even send it as an email attachment.&lt;/p&gt;
&lt;p&gt;Whatever you do, don&#39;t start pasting globs of text into your support ticket. Keep the message area to a minimum and link to or attach supplemental information as needed.&lt;/p&gt;
&lt;h2 id=&quot;know-when-to-mark-things-as-%22urgent%22&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/how-to-get-faster-and-better-help-from-support/#know-when-to-mark-things-as-%22urgent%22&quot;&gt;Know when to mark things as &amp;quot;urgent&amp;quot;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It&#39;s true. Not every issue you submit to support is urgent, so think twice before you check that box or litter the subject line with words like &amp;quot;critical&amp;quot; and &amp;quot;important.&amp;quot;&lt;/p&gt;
&lt;p&gt;So when exactly is something urgent? It really depends on your circumstance. I have a user who puts &amp;quot;urgent&amp;quot; on pretty much every support ticket he opens up, and I would seldom consider any of his requests to be urgent. They&#39;re urgent to him, but to nobody else. This desensitizes the word whenever I see it attached to one of his tickets. Remember the boy who cried wolf?&lt;/p&gt;
&lt;p&gt;Think of it like this. If you&#39;re looking out your living room window and see a suspicious person walking down the street, you&#39;d call the local police to give them a heads up (not urgent). But if you&#39;re looking out that same window and see a suspicious person breaking into your neighbor&#39;s house, you&#39;d call 911 (urgent).&lt;/p&gt;
&lt;p&gt;Is your issue worth dialing your support team&#39;s 911 hotline? If so, it&#39;s probably urgent.&lt;/p&gt;
&lt;h2 id=&quot;don&#39;t-email-your-password&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/how-to-get-faster-and-better-help-from-support/#don&#39;t-email-your-password&quot;&gt;Don&#39;t email your password&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A support person should never ask you for your password. They have ways of accessing your account securely without having you send your login credentials through a ticket system or email. Don&#39;t volunteer it to them, either, because every time they hit &amp;quot;reply&amp;quot; or &amp;quot;forward&amp;quot; your password might be getting sent across the Internet in plain-text.&lt;/p&gt;
&lt;p&gt;In some cases, like Media Temple, you&#39;ll need to generate a support pin to verify ownership of your account before calling. That&#39;s fine, because the pin is time-sensitive and can only be generated by you. However, they will never ask for your password in a support ticket or email.&lt;/p&gt;
&lt;p&gt;If you haven&#39;t already, you should probably train your brain to throw a red flag whenever anyone asks you for your password.&lt;/p&gt;
&lt;h2 id=&quot;be-patient&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/how-to-get-faster-and-better-help-from-support/#be-patient&quot;&gt;Be patient&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Last but not least, give the support team time to respond. One of my services promises a 24-hour response time — and we deliver on that 99.9% of the time. That&#39;s not an easy feat for a bootstrapped company serving users all over the world, but it doesn&#39;t stop people from submitting multiple requests, often less than a couple hours apart.&lt;/p&gt;
&lt;p&gt;You have to have patience. Don&#39;t submit a ticket and immediately jump on Facebook, Twitter, and every other platform you can find to submit the same request. It&#39;s rude, it&#39;s annoying, and it requires more time for support to respond. It can also confuse teams who manage support differently through various channels.&lt;/p&gt;
&lt;p&gt;Remember, you&#39;re speaking with real people out there. Even though support issues can be difficult and frustrating, keep your cool, be responsive, and be polite. I promise, you&#39;ll get much better support that way!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Swapping variables with JavaScript</title>
		<link href="https://www.abeautifulsite.net/posts/swapping-variables-with-javascript/"/>
		<updated>2014-08-04T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/swapping-variables-with-javascript/</id>
		<content type="html">&lt;p&gt;Swapping the value of two variables normally takes three lines and a temporary variable. What if I told you there was an easier way to do this with JavaScript?&lt;/p&gt;
&lt;h2 id=&quot;traditional-method&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/swapping-variables-with-javascript/#traditional-method&quot;&gt;Traditional method&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The goal is to swap the values of &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;. The textbook method for doing this looks something like this:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; b &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; c&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

c &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
a &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
b &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; c&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, we&#39;ve introduced another variable called &lt;code&gt;c&lt;/code&gt; to temporarily store the original value of &lt;code&gt;a&lt;/code&gt; during the swap. But can we do it without &lt;code&gt;c&lt;/code&gt;?&lt;/p&gt;
&lt;h2 id=&quot;one-line-method&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/swapping-variables-with-javascript/#one-line-method&quot;&gt;One-line method&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This trick uses an array to perform the swap. Take a second to wrap your head around it:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;b &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are a few things happening here, so if you&#39;re still having trouble understanding how or why this works, I&#39;ll explain:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We&#39;re utilizing an array where the first index is the value of &lt;code&gt;a&lt;/code&gt; and the second index is the value of  &lt;code&gt;b&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;a&lt;/code&gt; is set to the value of &lt;code&gt;b&lt;/code&gt; when the array is created&lt;/li&gt;
&lt;li&gt;&lt;code&gt;b&lt;/code&gt; is set to the first index of the array, which is  a&lt;/li&gt;
&lt;li&gt;MAGIC&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;While this trick definitely saves you a few lines of code and a temp variable, be cautious when using it. It&#39;s doesn&#39;t help that whole code clarity thing.&lt;/p&gt;
&lt;p&gt;Want to learn another cool way to swap variables? If you&#39;re a math buff, you&#39;ll like the &lt;a href=&quot;http://chris-taylor.github.io/blog/2013/02/25/xor-trick/&quot;&gt;xor trick&lt;/a&gt;.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>The next version of PHP may very well be 7</title>
		<link href="https://www.abeautifulsite.net/posts/the-next-version-of-php-may-very-well-be-7/"/>
		<updated>2014-08-01T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/the-next-version-of-php-may-very-well-be-7/</id>
		<content type="html">&lt;p&gt;We&#39;ve been hearing about PHP 6 since 2005, but nothing has been brought to fruition yet. In fact, the project was so plagued with problems that in 2010, &lt;a href=&quot;http://www.computerworld.com/s/article/9222419/PHP_5.4_emerges_with_best_of_abandoned_PHP_6.0&quot;&gt;it was abandoned&lt;/a&gt;. It almost felt like PHP would be perpetually stuck at version 5.&lt;/p&gt;
&lt;p&gt;Except now there&#39;s talk about another major release. It could be PHP 6, or maybe PHP 7. Between developers, there&#39;s &lt;a href=&quot;https://wiki.php.net/rfc/php6&quot;&gt;a hot debate&lt;/a&gt; over what the next major PHP release will be called.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The reason why this question even comes up, is that there has been a previous attempt at a new major version, which was started in 2005 and abandoned in 2010 due to difficulties in the Unicode implementation. Apart from language-integrated Unicode support, most features added for that version were integrated either in PHP 5.3 or PHP 5.4.&lt;/p&gt;
&lt;p&gt;This previous attempt at a new major version was also developed under the name of PHP 6 and as such there are various resources referring to it, including a number of books. There is concern that there might be confusion between the abandoned previous attempt and the work that is currently happening.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you&#39;re not familiar with what happened with the original PHP 6, you can read more its unfortunate demise &lt;a href=&quot;http://en.wikipedia.org/wiki/PHP#PHP_6_and_Unicode&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Given that the entire Internet was anticipating a PHP version that will never actually ship, it&#39;s probably better to stick with PHP 7.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>SVG has a logo</title>
		<link href="https://www.abeautifulsite.net/posts/svg-has-a-logo/"/>
		<updated>2014-08-01T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/svg-has-a-logo/</id>
		<content type="html">&lt;p&gt;HTML5 was the first to get an &lt;a href=&quot;http://www.w3.org/html/logo/&quot;&gt;official logo&lt;/a&gt;. Web designers rejoiced, some even hacking together matching logos &lt;a href=&quot;http://www.bobbyberberyan.com/2012/03/html-5-css-3-logos/&quot;&gt;for CSS&lt;/a&gt;. But did you know that SVG also has an official logo, and it&#39;s — flowery?&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/svg-logo.png&quot; alt=&quot;SVG logo (without text)&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The W3C describes it as:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The flower-like structure of the SVG logo evokes creativity and growth, while the connected nodes indicate integration with other technologies.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The logo was based off a design by &lt;a href=&quot;http://www.root2art.co.uk/svg_logo_download/index.php&quot;&gt;Harvey Rayner&lt;/a&gt;. According to the W3C:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It was selected by the SVG Working Group from among hundreds of entries in a contest conducted in 2006 by supporters and vendors of the SVG format.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It&#39;s a very symbolic representation of an otherwise difficult technology to sum up in an image. I&#39;d say it&#39;s a decent fit, but the version without text might confuse people.&lt;/p&gt;
&lt;p&gt;What do you think of the SVG logo? Have you seen it used anywhere? I have to be honest, I&#39;m on the Internet quite a bit and only stumbled across this yesterday. I wonder what other cool logos I&#39;m missing out on.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>A user interface is like a joke</title>
		<link href="https://www.abeautifulsite.net/posts/a-user-interface-is-like-a-joke/"/>
		<updated>2014-08-01T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/a-user-interface-is-like-a-joke/</id>
		<content type="html">&lt;p&gt;When I hear a simile like this, it&#39;s hard to not share. It&#39;s not so much an analogy as it is a good rule of thumb:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A user interface is like a joke. If you have to explain it, it&#39;s not that good.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And I&#39;ve heard some websites tell pretty bad jokes...&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Parsing URLs in JavaScript</title>
		<link href="https://www.abeautifulsite.net/posts/parsing-urls-in-javascript/"/>
		<updated>2013-10-24T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/parsing-urls-in-javascript/</id>
		<content type="html">&lt;p&gt;There&#39;s an excellent trick to &lt;a href=&quot;https://gist.github.com/jlong/2428561&quot;&gt;parsing URLs in JavaScript&lt;/a&gt;, which was introduced last year by John Long over on GitHub. This technique works great, but the resulting &lt;code&gt;search&lt;/code&gt; property will be a raw query string. This isn&#39;t very useful if you need to access certain variables in said query string. Thus, the following function expands on this paradigm, providing an additional property that contains an object based on the original query string.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parseURL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; parser &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;a&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; searchObject &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token comment&quot;&gt;// Let the browser do the work&lt;/span&gt;
	parser&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;href &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token comment&quot;&gt;// Convert query string to object for convenience&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; queries &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; parser&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;search&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;^&#92;?&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;&amp;amp;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; queries&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; split &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; queries&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;=&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		searchObject&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;split&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; split&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token literal-property property&quot;&gt;protocol&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; parser&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;protocol&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token literal-property property&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; parser&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;host&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token literal-property property&quot;&gt;hostname&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; parser&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hostname&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token literal-property property&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; parser&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;port&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token literal-property property&quot;&gt;pathname&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; parser&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pathname&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token literal-property property&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; parser&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;search&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token literal-property property&quot;&gt;searchObject&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; searchObject&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token literal-property property&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; parser&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hash
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&#39;s try it!&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; url &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parseURL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;https://example.com/index.html?q=test&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here&#39;s the result:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token literal-property property&quot;&gt;protocol&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;https:&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token literal-property property&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;example.com&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token literal-property property&quot;&gt;hostname&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;example.com&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token literal-property property&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token literal-property property&quot;&gt;pathname&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;/index.html&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token literal-property property&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;?q=test&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token literal-property property&quot;&gt;searchObject&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;test&#39;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token literal-property property&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content>
	</entry>
	
	<entry>
		<title>An icon converter that supports multiple sizes and transparency</title>
		<link href="https://www.abeautifulsite.net/posts/an-icon-converter-that-supports-multiple-sizes-and-transparency/"/>
		<updated>2013-09-19T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/an-icon-converter-that-supports-multiple-sizes-and-transparency/</id>
		<content type="html">&lt;p&gt;If you&#39;re looking for an online utility to convert JPEG, PNG, or GIF images to ICO format, here&#39;s one that does exactly that. It supports full transparency when converting 24-bit PNGs and even lets you combine multiple resolutions into one icon file — perfect for generating favicons.&lt;/p&gt;
&lt;p&gt;The name of the tool is &lt;a href=&quot;http://www.icoconverter.com/&quot;&gt;ICO Converter&lt;/a&gt; and, while the design of the page isn&#39;t very flashy, it works exceptionally well. Give it a try and start making some icons!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Validating URLs and email addresses in PHP</title>
		<link href="https://www.abeautifulsite.net/posts/validating-urls-and-email-addresses-in-php/"/>
		<updated>2013-09-18T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/validating-urls-and-email-addresses-in-php/</id>
		<content type="html">&lt;p&gt;This is a simple method for validating both email addresses and URLs. Using PHP&#39;s &lt;code&gt;filter_var()&lt;/code&gt; function, it&#39;s actually very easy and doesn&#39;t require regular expressions. The following wrapper functions force a true boolean response, so you can use them safely in your logic.&lt;/p&gt;
&lt;h2 id=&quot;email-addresses&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/validating-urls-and-email-addresses-in-php/#email-addresses&quot;&gt;Email addresses&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;is_email&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$email&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;filter_var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$email&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;FILTER_VALIDATE_EMAIL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token constant boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;urls&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/validating-urls-and-email-addresses-in-php/#urls&quot;&gt;URLs&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;is_url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;filter_var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;FILTER_VALIDATE_URL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token constant boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you choose to not use the wrappers, just remember that &lt;code&gt;filter_var()&lt;/code&gt; doesn&#39;t always return a boolean value. It will return the original string on success, and &lt;code&gt;false&lt;/code&gt; on failure..&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Semantic version numbers</title>
		<link href="https://www.abeautifulsite.net/posts/semantic-version-numbers/"/>
		<updated>2013-08-21T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/semantic-version-numbers/</id>
		<content type="html">&lt;p&gt;Gone are the days of arbitrarily assigning version numbers to every new software release. With &lt;a href=&quot;http://semver.org/&quot;&gt;semantic versioning&lt;/a&gt;, the question of how and when to bump versions is made simple.&lt;/p&gt;
&lt;p&gt;According to &lt;a href=&quot;http://semver.org/&quot;&gt;semver.org&lt;/a&gt;, the syntax for version numbers should go like this: &lt;code&gt;MAJOR.MINOR.PATCH&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;When you release a new version, it&#39;s easy to determine which numbers to increment:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;MAJOR&lt;/code&gt; version when you make incompatible API changes,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MINOR&lt;/code&gt; version when you add functionality in a backwards-compatible manner, and&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PATCH&lt;/code&gt; version when you make backwards-compatible bug fixes.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The entire spec is actually quite short and simple (for a spec), but the concepts therein will [hopefully] change the way developers version their software in the future. While many projects already follow similar conventions, there are still many that don&#39;t. This is especially true in the case of smaller projects, where developers seem to arbitrarily bump version numbers without considering the impact such changes may have on their users.&lt;/p&gt;
&lt;p&gt;If you don&#39;t have an existing standard for versioning your software, help make the world a better place and consider adopting SemVer in your next project!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>There&#39;s a reason that Bootstrap 3 has ugly buttons</title>
		<link href="https://www.abeautifulsite.net/posts/theres-a-reason-that-bootstrap-3-has-ugly-buttons/"/>
		<updated>2013-08-20T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/theres-a-reason-that-bootstrap-3-has-ugly-buttons/</id>
		<content type="html">&lt;p&gt;It&#39;s true. Everyone loves Bootstrap&#39;s buttons...at least they did until &lt;a href=&quot;http://blog.getbootstrap.com/2013/08/19/bootstrap-3-released/&quot;&gt;3.0 came out&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But before you get upset at &lt;a href=&quot;https://twitter.com/mdo&quot;&gt;@mdo&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/fat&quot;&gt;@fat&lt;/a&gt; for what many mistake to be a move towards the anti-skeuomorphic design trend, you should realize there&#39;s more than meets the eye behind the decision to make buttons flat and &amp;quot;ugly&amp;quot; in Bootstrap 3.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/bootstrap-buttons.png&quot; alt=&quot;Bootstrap 3 default buttons&quot; /&gt;&lt;/p&gt;
&lt;p&gt;As Mark Otto &lt;a href=&quot;https://github.com/twbs/bootstrap/pull/6342#issuecomment-12332378&quot;&gt;stated&lt;/a&gt; on GitHub while Bootstrap 3 was under development:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Gradients and other embellishments have temporarily been removed while I focus on other things. It has nothing to do with skeuomorphism or anything like that.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There were plenty of follow ups, both for and against the flat, gradient-less buttons. Unfortunately, what a lot of folks don&#39;t realize is that Bootstrap is intended to be a &lt;em&gt;starting point&lt;/em&gt; for their projects, not an end-all solution for front-end development. In other words, Bootstrap is &lt;em&gt;supposed&lt;/em&gt; to be customized, and adding gradients and other arbitrary styles to the core simply makes that harder to do.&lt;/p&gt;
&lt;p&gt;Aside from that, when things look too good out-of-the-box, people tend to leave them that way. We saw that so much with Bootstrap 2.x that it spawned blog posts imploring people to &lt;a href=&quot;http://css.dzone.com/articles/please-stop-using-twitter&quot;&gt;stop using Bootstrap&lt;/a&gt; (or at least &lt;a href=&quot;http://peteschuster.com/2013/06/stop-using-bootstrap-and-start-using-bootstrap/&quot;&gt;start using it right&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Ultimately, Bootstrap 3 encourages people to customize their implementation, and that&#39;s a good thing.&lt;/p&gt;
&lt;h2 id=&quot;a-less-mixin&#39;-for-prettier-buttons&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/theres-a-reason-that-bootstrap-3-has-ugly-buttons/#a-less-mixin&#39;-for-prettier-buttons&quot;&gt;A Less Mixin&#39; for Prettier Buttons&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you long for the good ol&#39; days of beautiful Bootstrap buttons, I may have a solution that you&#39;ll like. It&#39;s a &lt;a href=&quot;https://gist.github.com/claviska/6117193&quot;&gt;Less mixin&#39; for buttons&lt;/a&gt;, designed specifically for Bootstrap 3. It&#39;s easy to use and customize. Use it in conjunction with Bootstrap&#39;s Less files and you&#39;ll have nice, customized buttons with minimal effort. Here&#39;s a sample:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/bootstrap-buttons-mixin.png&quot; alt=&quot;Bootstrap 3 pretty buttons&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This mixin&#39; works in conjunction with default Bootstrap 3 styles, so you can change pretty much anything with ease. Consider this Gist a public domain offering, and use it however you like.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Whipping file inputs into shape with Bootstrap</title>
		<link href="https://www.abeautifulsite.net/posts/whipping-file-inputs-into-shape-with-bootstrap-3/"/>
		<updated>2013-08-08T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/whipping-file-inputs-into-shape-with-bootstrap-3/</id>
		<content type="html">&lt;p&gt;There are &lt;a href=&quot;http://www.quirksmode.org/dom/inputfile.html&quot;&gt;many&lt;/a&gt;, &lt;a href=&quot;https://coderwall.com/p/4etjja&quot;&gt;many&lt;/a&gt;, &lt;a href=&quot;http://viget.com/inspire/custom-file-inputs-with-a-bit-of-jquery&quot;&gt;many&lt;/a&gt; ways to hack a file input so it looks and behaves consistently across all browsers. There&#39;s even a pretty &lt;a href=&quot;http://markusslima.github.io/bootstrap-filestyle/&quot;&gt;slick plugin&lt;/a&gt; to help get the job done. Unfortunately, most of these solutions are cumbersome, prone to cross-browser issues, and require JavaScript.&lt;/p&gt;
&lt;p&gt;Today, I would like to propose a more fundamental approach for file inputs in Bootstrap 3 and 4.&lt;/p&gt;
&lt;h2 id=&quot;modern-approach-(ie9%2B)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/whipping-file-inputs-into-shape-with-bootstrap-3/#modern-approach-(ie9%2B)&quot;&gt;Modern approach (IE9+)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let&#39;s start by nesting a button inside a &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt;, adding the appropriate button classes to style it as we want:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;btn btn-default btn-file&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  Browse &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;file&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value css language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;legacy-approach-(ie8-and-below)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/whipping-file-inputs-into-shape-with-bootstrap-3/#legacy-approach-(ie8-and-below)&quot;&gt;Legacy approach (IE8 and below)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you need support for old IE, you can use this legacy approach. Instead of a &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt;, wrap your button in a &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;btn btn-default btn-file&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  Browse &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;file&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then apply the following CSS:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.btn-file&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; relative&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;overflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; hidden&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;.btn-file input[type=file]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; absolute&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;min-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;min-height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;text-align&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; right&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;alpha&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;opacity=0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;outline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; white&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;cursor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; inherit&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; block&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;customizing-the-button&#39;s-appearance&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/whipping-file-inputs-into-shape-with-bootstrap-3/#customizing-the-button&#39;s-appearance&quot;&gt;Customizing the button&#39;s appearance&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So far so good. Whether you&#39;re using the modern approach or the legacy approach, clicking on the &amp;quot;button&amp;quot; will trigger the file input. As a bonus, it will also acquire the &lt;code&gt;:hover&lt;/code&gt; and &lt;code&gt;:active&lt;/code&gt; pseudo classes so it behaves like a real button too.&lt;/p&gt;
&lt;p&gt;You can use these buttons like you normally would…by themselves, in a button group, or even in an input group.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/bootstrap-file-input-example.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;providing-feedback&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/whipping-file-inputs-into-shape-with-bootstrap-3/#providing-feedback&quot;&gt;Providing feedback&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now with the hard part out of the way, it&#39;s a good practice to provide users with a bit of feedback about their selection. A touch of jQuery magic will keep an eye on your file inputs and fire an event called &lt;code&gt;fileselect&lt;/code&gt; when a file is chosen:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;change&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;:file&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; input &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; numFiles &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;files &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;files&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; label &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;&#92;&#92;&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;/&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;.*&#92;/&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trigger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;fileselect&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;numFiles&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; label&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&#39;s an example to demonstrate the event:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ready&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;:file&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;fileselect&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;event&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; numFiles&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;numFiles&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;label&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can use the &lt;code&gt;numFiles&lt;/code&gt; or &lt;code&gt;label&lt;/code&gt; parameter to show users the name of the file that was selected and, if applicable, how many. Alternatively, you could elect to use the standard &lt;strong&gt;change&lt;/strong&gt; event and handle the label yourself.&lt;/p&gt;
&lt;p&gt;This method was tested to work in IE8–IE11 and recent versions of Chrome, Safari, Firefox, and Opera.&lt;/p&gt;
&lt;h2 id=&quot;see-it-in-action&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/whipping-file-inputs-into-shape-with-bootstrap-3/#see-it-in-action&quot;&gt;See it in action&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a live demo that you can tinker with, &lt;a href=&quot;http://codepen.io/claviska/pen/vAgmd/&quot;&gt;view the demo CodePen&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;May 20, 2016: added the modern approach and updated the demo.&lt;/em&gt;&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Tips for the aspiring web developer</title>
		<link href="https://www.abeautifulsite.net/posts/tips-for-the-aspiring-web-developer/"/>
		<updated>2012-12-17T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/tips-for-the-aspiring-web-developer/</id>
		<content type="html">&lt;p&gt;So you want to be a web developer...excellent choice! It&#39;s a very rewarding position that can be a lot more fun than most other programming jobs. However, before you take the plunge into a career in web development, there are a few things you should probably consider.&lt;/p&gt;
&lt;h2 id=&quot;a-different-way-of-life&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/tips-for-the-aspiring-web-developer/#a-different-way-of-life&quot;&gt;A different way of life&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I&#39;m not going to start by telling you that you&#39;ll be working in at least five different programming languages on a daily basis. Nor am I going to talk about the rapidly changing technologies and standards that you&#39;ll need to keep up with. And I&#39;m not even going to mention the multitude of browser quirks that will keep you up into early hours of the morning. All that will come with experience. My goal is to help you understand the type of career — or perhaps the lifestyle — that you&#39;re about to undertake.&lt;/p&gt;
&lt;p&gt;As a web developer, the type of organization you work for makes a huge difference in how your career will evolve. Chances are, if you&#39;re seriously considering web development as a career, you&#39;ve already spent some of your own time dabbling in HTML, CSS, JavaScript, and one or more server-side scripting languages. You probably discovered how much fun it can be to make something that millions of people could potentially see. If so, you have passion...and that&#39;s a good thing.&lt;/p&gt;
&lt;h2 id=&quot;it&#39;s-ok-to-be-passionate&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/tips-for-the-aspiring-web-developer/#it&#39;s-ok-to-be-passionate&quot;&gt;It&#39;s ok to be passionate&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Passion drives creativity. It&#39;s what keeps you working on something for hours on end simply because you want to. It&#39;s what eats away at your nights and weekends. It&#39;s what sucks the spirit out of your social life. If you don&#39;t have that drive, chances are you&#39;re not going to enjoy being a web developer.&lt;/p&gt;
&lt;p&gt;In my experience, passionate people tend to have their own way of doing things. The countless hours they spend educating themselves outside the realm of academia gives them insight that people without that dedication will never understand. They change their methods as technology evolves, are generally forward-thinking, and appreciate the &amp;quot;laws&amp;quot; of the web. They take their time to do things right. They care about quality, their user&#39;s experience, and the final product. Employers don&#39;t always like that, but that doesn&#39;t mean it&#39;s a bad thing.&lt;/p&gt;
&lt;h2 id=&quot;%22right%22-is-not-always-right&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/tips-for-the-aspiring-web-developer/#%22right%22-is-not-always-right&quot;&gt;&amp;quot;Right&amp;quot; is not always right&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Over the past decade, I&#39;ve had the opportunity to work (as a web developer) for a manufacturing company, an academic institution, numerous web design firms (as a contractor), and for myself. I surround myself as much as possible with individuals who are in the same field as I am. Through many experiences and many discussions, I&#39;ve come to realize that doing the &amp;quot;right&amp;quot; thing is not always what employers want you to do, particularly when budgets and deadlines are involved.&lt;/p&gt;
&lt;p&gt;That&#39;s a hard realization to come to when you&#39;re passionate about what you do. Maybe you wanted to spend extra time refactoring that code you wrote — it &amp;quot;works&amp;quot;, but there&#39;s a better way to do it — except the budget doesn&#39;t allow for it. Maybe the client needed it out yesterday and you don&#39;t have time to finish polishing off the interface you&#39;ve been working on. Everyone&#39;s going to know you&#39;re responsible for it, but it&#39;s not perfect yet and people may think your work is substandard. These things can be hard to deal with as a developer, so be prepared to sacrifice the quality of your work — or put in extra time off-the-clock — when budgets and timelines don&#39;t permit.&lt;/p&gt;
&lt;h2 id=&quot;never-stop-learning&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/tips-for-the-aspiring-web-developer/#never-stop-learning&quot;&gt;Never stop learning&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Where you work also plays a role in how your skills as a web developer evolve. Organizations tend to have their own standards and best practices in place that may or may not be as current as the rest of the world. I&#39;ve seen design firms who are at least 10 years behind in their development methodologies. Their employees aren&#39;t encouraged and, in some cases, aren&#39;t permitted to use modern technologies and techniques. While this is obviously terrible for the organization, it&#39;s also detrimental to the development of its employees.&lt;/p&gt;
&lt;p&gt;If you find yourself in this position at any point in your career, you should talk to your management about the policies that are holding your organization back. If they&#39;re too close-minded to consider anything outside their comfort zone, it may be time to find a position elsewhere. When there&#39;s no opportunity to learn new things, you&#39;ll likely get burned out and fall behind new trends in technology. That makes you less attractive to future employers, and overall, it&#39;s really not much fun.&lt;/p&gt;
&lt;p&gt;Additionally, it&#39;s OK to make mistakes provided you learn from them. Always, always, always learn from your mistakes. And don&#39;t be afraid to admit when you screw up. You&#39;re human. It will happen. Owning up to things will garner you far more respect and wisdom than placing the blame on someone or something else.&lt;/p&gt;
&lt;h2 id=&quot;be-prepared-to-give-up-sleep&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/tips-for-the-aspiring-web-developer/#be-prepared-to-give-up-sleep&quot;&gt;Be prepared to give up sleep&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There have been many, many, many nights where I&#39;ve watched the sun set, then rise, and then set again. It doesn&#39;t happen every day, but it happens. It&#39;s something you have to expect as a developer. Whether it&#39;s your own product launch or a really long workday that got prolonged because a server crashed, it&#39;s going to happen.&lt;/p&gt;
&lt;p&gt;Even when I had an eight-to-five job, there were still nights where important things needed to be done. A lot of times that meant working through the night. In fact, many tech positions share this quality, and developers are definitely no exception.&lt;/p&gt;
&lt;h2 id=&quot;find-a-routine&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/tips-for-the-aspiring-web-developer/#find-a-routine&quot;&gt;Find a routine&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It&#39;s not always possible, but following a routine as often as you can will reduce stress, anxiety, and fatigue. Eat at the right times and try to get enough sleep. If you get caught up in a day from hell that shatters your daily routine (which you will at some point), do what you can to get back on track.&lt;/p&gt;
&lt;p&gt;I can&#39;t stress this point enough.&lt;/p&gt;
&lt;p&gt;Put down your phone when it&#39;s bedtime. Wake up when your alarm goes off. If you set aside some time for your significant other or your friends, give yourself that time to recenter. This may seem to contradict some of the points I&#39;ve made previously, but this type of career isn&#39;t just a career — it&#39;s a lifestyle. You have to know how to balance things. Realize your limits and know when to keep going, but also know when to stop.&lt;/p&gt;
&lt;p&gt;It&#39;s not as easy as it sounds. In fact, it&#39;s something that I continue to have problems with after many years in the field. However, when I do get back into a routine, I notice a clear difference in my attitude, health, performance, and overall well-being. This is really more of an issue for freelancers and startups, but even the eight-to-fiver can benefit from following a good daily routine.&lt;/p&gt;
&lt;h2 id=&quot;exercise-your-mind-and-your-body&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/tips-for-the-aspiring-web-developer/#exercise-your-mind-and-your-body&quot;&gt;Exercise your mind and your body&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is another thing that a lot of web developers who I meet seem to neglect. No matter how many hours you spend doing it, a code marathon isn&#39;t going to make your body healthy. And if your body isn&#39;t healthy, your mind will suffer.&lt;/p&gt;
&lt;p&gt;Make it part of your routine. Spend at least 30 minutes a day doing some kind of exercise. Even if you just walk around outside for 30 minutes, it&#39;s better than nothing.&lt;/p&gt;
&lt;h2 id=&quot;get-in-the-zone&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/tips-for-the-aspiring-web-developer/#get-in-the-zone&quot;&gt;Get in the zone&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Any web developer knows what it&#39;s like, and how frustrating it can be when a distraction takes you out of the zone and blows your developmental buzz. Discover what helps you get in the zone and make it happen. Turn on the right type of music (to me, techno does the trick; anything else and I find myself getting caught up in the lyrics). Turn off your email and only check it at scheduled times. Turn off your cell phone (Android and iOS both have awesome do-not-disturb features). Turn off your instant messager.&lt;/p&gt;
&lt;p&gt;Find your zen. Become one with your code. And then watch your productivity rage.&lt;/p&gt;
&lt;h2 id=&quot;keep-your-drive&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/tips-for-the-aspiring-web-developer/#keep-your-drive&quot;&gt;Keep your drive&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;No matter where you work or who you work for, it&#39;s important to keep your drive. A successful developer will put in the extra hours to make an amazing product that impresses his manager and clients. Don&#39;t get discouraged by a missed deadline — rectify it and explain how you needed the extra time to finish it properly...then try harder to be punctual next time. Learn new things as much as possible and integrate them into your projects when applicable. This keeps you up to date with technology and makes you more valuable to potential employers. If your organization fears new technology, stand up for what you believe in and encourage them to evolve their policies and practices.&lt;/p&gt;
&lt;p&gt;Just remember, the job you have now is just a stepping stone in the river of your career. Don&#39;t let anyone pull you into the water and drown out your dreams.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Down with the share widget!</title>
		<link href="https://www.abeautifulsite.net/posts/down-with-the-share-widget/"/>
		<updated>2012-12-14T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/down-with-the-share-widget/</id>
		<content type="html">&lt;p&gt;In a world dominated by social media, it&#39;s natural to want visitors to share your content with friends and followers. This really isn&#39;t a bad thing, but how you go about encouraging them can actually be &lt;em&gt;discouraging&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-rise-of-the-%22share%22-widget&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/down-with-the-share-widget/#the-rise-of-the-%22share%22-widget&quot;&gt;The rise of the &amp;quot;share&amp;quot; widget&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Six years ago, Twitter &lt;em&gt;wasn&#39;t&lt;/em&gt; all over the news. Facebook had &lt;em&gt;just&lt;/em&gt; opened itself up to any user over the age of 13. You didn&#39;t see social media logos on television commercials or on every box of cereal at the supermarket. The guy on the radio wasn&#39;t screaming at you to &amp;quot;like&amp;quot; this and that. Those were the good old days.&lt;/p&gt;
&lt;p&gt;Today, everyone from the kid next door to &lt;a href=&quot;http://twitter.com/pontifex&quot;&gt;the pope&lt;/a&gt; has a Twitter account. Major retailers and brands are reaching out to their customers through Facebook, providing them with offers and incentives faster than they ever could before. Companies are tackling customer support by responding within hours or even minutes to angry consumers who voice their opinions to the world. Social media is good stuff, and even our technophobic grandmothers are getting on board.&lt;/p&gt;
&lt;p&gt;The point is, everyone knows about social media now. It&#39;s built into our desktops, tablets, and phones. There are a multitude of apps that make posting content to your favorite service a breeze. So why are we still plastering &amp;quot;share&amp;quot; widgets all over our sites?&lt;/p&gt;
&lt;p&gt;I was recently speaking with a good friend of mine about this. We both have websites, and we both had those tacky, distracting &amp;quot;share&amp;quot; widgets on them at some point. We were social when social wasn&#39;t cool.&lt;/p&gt;
&lt;p&gt;But now, it seems like every site we come across has some kind of obtrusive social-sharing widget included on every single page. &lt;em&gt;Share this, tweet that, blah, blah, blah&lt;/em&gt;...it&#39;s just as distracting and tacky as a big ugly banner ad — and people become desensitized by that sort of thing.&lt;/p&gt;
&lt;h2 id=&quot;it&#39;s-usually-not-worth-it&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/down-with-the-share-widget/#it&#39;s-usually-not-worth-it&quot;&gt;It&#39;s usually not worth it&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;That&#39;s a pretty bold statement, but let&#39;s use the very popular tech blog &lt;a href=&quot;http://mashable.com/&quot;&gt;Mashable&lt;/a&gt; as an example. Mashable reaches out to tech nuts — people who use social media on an unhealthy basis. There&#39;s no shortage of social media sharing in Mashable&#39;s audience, so if anyone can pull this off, it would be them.&lt;/p&gt;
&lt;p&gt;Considering Mashable &lt;a href=&quot;http://mashable.com/about/&quot;&gt;boasts&lt;/a&gt; 20 million monthly visitors (as well as six million social media followers), you&#39;d think their &amp;quot;share&amp;quot; widgets would have staggering numbers. On the contrary, the average post only appears to get between 500 and 900 collective &amp;quot;shares&amp;quot; in its first 48 hours of existence (an article&#39;s prime exposure period). Here&#39;s an example from an article posted a couple days ago:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/mashable-share.png&quot; alt=&quot;Mashable&#39;s share widget&quot; /&gt;&lt;/p&gt;
&lt;p&gt;While it&#39;s impossible to determine the actual number of visits to each article on Mashable, it quickly becomes obvious that the percentage of visitors who bother sharing them is extremely low.&lt;/p&gt;
&lt;p&gt;If a news giant such as Mashable — who garners over 20 million visitors a month — can only pull in a few thousand shares per article, how many do you think your site will be able to pull in?&lt;/p&gt;
&lt;h2 id=&quot;encourage-them-without-encouraging-them&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/down-with-the-share-widget/#encourage-them-without-encouraging-them&quot;&gt;Encourage them without encouraging them&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So how do you encourage users to share your content without slapping an annoying badge or button on your site? The answer comes down to the most fundamental rule of successful bloggers:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Post awesome stuff that people want to read!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;No matter how many &amp;quot;like&amp;quot; or &amp;quot;share&amp;quot; widgets you put on your page, if your content sucks, people aren&#39;t going to pass it along to their friends. But if your content is interesting, people will share it whether or not those widgets even exist.&lt;/p&gt;
&lt;p&gt;If you think it&#39;s all about making it easier for users to share your content...think again. Social integration is built right into most devices these days. You can Tweet directly from the &lt;a href=&quot;http://www.cultofmac.com/194772/enable-twitter-in-mountain-lion-notification-center-os-x-tips/&quot;&gt;Notification Center&lt;/a&gt; in OS X. iOS has both &lt;a href=&quot;http://mashable.com/2011/06/06/apple-twitter-ios5/&quot;&gt;Twitter&lt;/a&gt; and &lt;a href=&quot;http://mashable.com/2012/06/11/apple-facebook/&quot;&gt;Facebook&lt;/a&gt; integrated right into the operating system. Windows 8 connects with those and many more services through its &lt;a href=&quot;http://www.pcworld.com/article/2013554/windows-8-deep-dive-get-to-know-the-people-app.html&quot;&gt;People App&lt;/a&gt;. And all of that goes without mentioning the &lt;a href=&quot;https://play.google.com/store/apps/category/SOCIAL?feature=category-nav&quot;&gt;many&lt;/a&gt;, &lt;a href=&quot;https://itunes.apple.com/us/genre/ios-social-networking/id6005?mt=8&quot;&gt;many&lt;/a&gt; apps that are available on every platform to do the very same things.&lt;/p&gt;
&lt;p&gt;Six years ago, when the average person had no idea what social media was, &amp;quot;share&amp;quot; widgets became a fad. Now, since social media is more than apparent in all our lives, they serve little more than to beg people to do something they would already have done if they really wanted to. Remember, quality is far more important than quantity when it comes to blogging. Besides, wouldn&#39;t you rather have people &lt;em&gt;want&lt;/em&gt; to share your content instead of &lt;em&gt;begging&lt;/em&gt; them to?&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Feature detection for CSS transitions via jQuery $.support</title>
		<link href="https://www.abeautifulsite.net/posts/feature-detection-for-css-transitions-via-jquery-support/"/>
		<updated>2012-12-09T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/feature-detection-for-css-transitions-via-jquery-support/</id>
		<content type="html">&lt;p&gt;When working with CSS transitions, the need to detect whether or not the browser supports them may arise.  It can be of particular use when working with the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/CSS/Using_CSS_transitions#Detecting_the_completion_of_a_transition&quot;&gt;&lt;code&gt;transitionend&lt;/code&gt;&lt;/a&gt; event, which won&#39;t fire in unsupportive browsers.&lt;/p&gt;
&lt;p&gt;After finding a number of questionable solutions, I came across this &lt;a href=&quot;https://gist.github.com/373874&quot;&gt;gist&lt;/a&gt; that extends jQuery&#39;s &lt;code&gt;$.support&lt;/code&gt; nicely.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;$&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;support&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;transition &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; thisBody &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;documentElement&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    thisStyle &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; thisBody&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    support &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; thisStyle&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;transition &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; thisStyle&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;WebkitTransition &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; thisStyle&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;MozTransition &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; thisStyle&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;MsTransition &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; thisStyle&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;OTransition &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; support&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The value of &lt;code&gt;$.support.transition&lt;/code&gt; will be &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt; depending on the browser&#39;s capabilities.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Access pages without the php extension using .htaccess</title>
		<link href="https://www.abeautifulsite.net/posts/access-pages-without-the-php-extension-using-htaccess/"/>
		<updated>2012-02-03T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/access-pages-without-the-php-extension-using-htaccess/</id>
		<content type="html">&lt;p&gt;There are a number of ways to make &amp;quot;clean URLs&amp;quot; work on your site, but this one is pretty straight forward.  It allows you to access &lt;code&gt;/any-page.php&lt;/code&gt; by simply going to &lt;code&gt;/any-page&lt;/code&gt;.  Just place the following into your &lt;code&gt;.htaccess&lt;/code&gt; file (and make sure that &lt;code&gt;mod_rewrite&lt;/code&gt; is enabled):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;RewriteEngine On
RewriteCond %{SCRIPT&#92;_FILENAME} !-d
RewriteRule ^(&#92;[^.&#92;]+)$ $1.php &#92;[NC,L&#92;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The nice thing about this is that it doesn&#39;t affect querystrings.  With this solution, both of these URLs are effectively the same:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http://example.com/page.php?id=123

http://example.com/page?id=123
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, the caveat is that you don&#39;t have &amp;quot;clean querystrings&amp;quot;, but it&#39;s a reasonable trade-off between &amp;quot;clean&amp;quot; and configuration.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Detecting mobile devices with JavaScript</title>
		<link href="https://www.abeautifulsite.net/posts/detecting-mobile-devices-with-javascript/"/>
		<updated>2011-11-23T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/detecting-mobile-devices-with-javascript/</id>
		<content type="html">&lt;p&gt;While I understand and value the concept of feature detection over browser detection, sometimes the need for knowing whether or not we&#39;re dealing with a mobile device arises. For in-depth device checking, you can rely on a complex library such as &lt;a href=&quot;http://blog.mobileesp.com/&quot;&gt;The MobileESP Project&lt;/a&gt;. But for simpler applications, the following snippet can be useful.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; isMobile &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;Android&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; navigator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userAgent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;Android&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;i&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;BlackBerry&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; navigator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userAgent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;BlackBerry&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;i&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;iOS&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; navigator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userAgent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;iPhone|iPad|iPod&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;i&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;Opera&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; navigator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userAgent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;Opera Mini&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;i&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;Windows&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; navigator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userAgent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;IEMobile&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;i&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      isMobile&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Android&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt;
      isMobile&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;BlackBerry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt;
      isMobile&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;iOS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt;
      isMobile&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Opera&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt;
      isMobile&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Windows&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While this doesn&#39;t account for &lt;em&gt;all&lt;/em&gt; mobile platforms, it will pick up the most popular ones out there.&lt;/p&gt;
&lt;h2 id=&quot;examples&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/detecting-mobile-devices-with-javascript/#examples&quot;&gt;Examples&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To check to see if the user is on any of the supported mobile devices:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;isMobile&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Mobile&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To check to see if the user is on a specific mobile device:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;isMobile&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;iOS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;iOS&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content>
	</entry>
	
	<entry>
		<title>Redirecting to and from the www subdomain with .htaccess</title>
		<link href="https://www.abeautifulsite.net/posts/redirecting-to-and-from-the-www-subdomain-with-htaccess/"/>
		<updated>2011-11-17T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/redirecting-to-and-from-the-www-subdomain-with-htaccess/</id>
		<content type="html">&lt;p&gt;Here are a few snippets that will come in handy if you ever need to redirect &lt;a href=&quot;http://www.example.com/&quot;&gt;www.example.com&lt;/a&gt; to &lt;a href=&quot;http://example.com/&quot;&gt;example.com&lt;/a&gt; or vice versa.  There are a number of similar methods out there, but I prefer these as you don&#39;t need to modify anything between development and production.&lt;/p&gt;
&lt;pre class=&quot;language-apacheconf&quot;&gt;&lt;code class=&quot;language-apacheconf&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# www.domain.com → domain.com&lt;/span&gt;
&lt;span class=&quot;token directive-block tag&quot;&gt;&lt;span class=&quot;token directive-block tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;IfModule&lt;/span&gt;&lt;span class=&quot;token directive-block-parameter attr-value&quot;&gt; mod_rewrite.c&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token directive-inline property&quot;&gt;RewriteCond&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;%{HTTPS}&lt;/span&gt; !=on
  &lt;span class=&quot;token directive-inline property&quot;&gt;RewriteCond&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;%{HTTP_HOST}&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt; ^www.(.+)$&lt;/span&gt; &lt;span class=&quot;token directive-flags keyword&quot;&gt;[NC]&lt;/span&gt;
  &lt;span class=&quot;token directive-inline property&quot;&gt;RewriteRule&lt;/span&gt; &lt;span class=&quot;token regex&quot;&gt;^ http://&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;%1&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;%{REQUEST_URI}&lt;/span&gt; &lt;span class=&quot;token directive-flags keyword&quot;&gt;[R=301,L]&lt;/span&gt;
&lt;span class=&quot;token directive-block tag&quot;&gt;&lt;span class=&quot;token directive-block tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;IfModule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# domain.com → www.domain.com&lt;/span&gt;
&lt;span class=&quot;token directive-block tag&quot;&gt;&lt;span class=&quot;token directive-block tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;IfModule&lt;/span&gt;&lt;span class=&quot;token directive-block-parameter attr-value&quot;&gt; mod_rewrite.c&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token directive-inline property&quot;&gt;RewriteEngine&lt;/span&gt; On
  &lt;span class=&quot;token directive-inline property&quot;&gt;RewriteCond&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;%{HTTPS}&lt;/span&gt; !=on
  &lt;span class=&quot;token directive-inline property&quot;&gt;RewriteCond&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;%{HTTP_HOST}&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt; !^www..+$&lt;/span&gt; &lt;span class=&quot;token directive-flags keyword&quot;&gt;[NC]&lt;/span&gt;
  &lt;span class=&quot;token directive-inline property&quot;&gt;RewriteRule&lt;/span&gt; &lt;span class=&quot;token regex&quot;&gt;^ http://www.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;%{HTTP_HOST}&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;%{REQUEST_URI}&lt;/span&gt; &lt;span class=&quot;token directive-flags keyword&quot;&gt;[R=301,L]&lt;/span&gt;
&lt;span class=&quot;token directive-block tag&quot;&gt;&lt;span class=&quot;token directive-block tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;IfModule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you plan on using these, you&#39;ll need to make sure you have the &lt;a href=&quot;http://httpd.apache.org/docs/current/mod/mod_rewrite.html&quot;&gt;mod_rewrite module&lt;/a&gt; enabled on your server.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>The SimpleImage library for PHP</title>
		<link href="https://www.abeautifulsite.net/posts/the-simple-image-library-for-php/"/>
		<updated>2011-11-16T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/the-simple-image-library-for-php/</id>
		<content type="html">&lt;p&gt;If you love working with PHP but hate the GD library, you&#39;ll love the Simple Image PHP class I&#39;m releasing today. This class takes the headache out of dealing with images and features over 25 useful methods.&lt;/p&gt;
&lt;p&gt;The class is incredibly simple to use.  The following two lines will load &lt;strong&gt;image.jpg&lt;/strong&gt;, flip it horizontally, rotate it 90 degrees, shrink it to fit within a 320x200 box, apply a sepia effect, convert it to a GIF, and save it to &lt;code&gt;result.gif&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$img&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;SimpleImage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;image.jpg&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;$img&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;flip&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;x&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;rotate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;90&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;best_fit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;320&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sepia&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;result.gif&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&#39;s a list of the supported methods:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;flip()&lt;/code&gt; - flips an image vertically or horizontally&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rotate()&lt;/code&gt; - rotates an image at the specified angle&lt;/li&gt;
&lt;li&gt;&lt;code&gt;auto_orient()&lt;/code&gt; - adjusts the orientation based on the image&#39;s EXIF data&lt;/li&gt;
&lt;li&gt;&lt;code&gt;resize()&lt;/code&gt; - resizes an image to the specified width/height&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fit_to_width()&lt;/code&gt; - proportionally resizes an image to the specified width&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fit_to_height()&lt;/code&gt; - proportionally resizes an image to the specified height&lt;/li&gt;
&lt;li&gt;&lt;code&gt;best_fit()&lt;/code&gt; - proportionally resizes an image to fit within the specified width/height&lt;/li&gt;
&lt;li&gt;&lt;code&gt;crop()&lt;/code&gt; - crop an image from x1/y1 to x2/y2&lt;/li&gt;
&lt;li&gt;&lt;code&gt;square_crop()&lt;/code&gt; - trim the image to a square and resize to the specified size&lt;/li&gt;
&lt;li&gt;&lt;code&gt;desaturate()&lt;/code&gt; - convert the image to grayscale&lt;/li&gt;
&lt;li&gt;&lt;code&gt;invert()&lt;/code&gt; - invert the image&lt;/li&gt;
&lt;li&gt;&lt;code&gt;brightness()&lt;/code&gt; - adjust the image&#39;s brightness&lt;/li&gt;
&lt;li&gt;&lt;code&gt;contrast()&lt;/code&gt; - adjust the image&#39;s contrast&lt;/li&gt;
&lt;li&gt;&lt;code&gt;colorize()&lt;/code&gt; - apply the colorize filter&lt;/li&gt;
&lt;li&gt;&lt;code&gt;edges()&lt;/code&gt; - apply the edges filter&lt;/li&gt;
&lt;li&gt;&lt;code&gt;emboss()&lt;/code&gt; - apply the emboss filter&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mean_remove()&lt;/code&gt; - apply the mean removal filter&lt;/li&gt;
&lt;li&gt;&lt;code&gt;blur()&lt;/code&gt; - apply selective or gaussian blur to the image&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sketch()&lt;/code&gt; - apply the sketch filter&lt;/li&gt;
&lt;li&gt;&lt;code&gt;smooth()&lt;/code&gt; - apply the smooth filter&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pixelate()&lt;/code&gt; - pixelate the image to blocks of the specified size&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sepia()&lt;/code&gt; - apply a simulated sepia effect&lt;/li&gt;
&lt;li&gt;&lt;code&gt;overlay()&lt;/code&gt; - overlay one image onto another to create a watermark effect&lt;/li&gt;
&lt;li&gt;&lt;code&gt;text()&lt;/code&gt; - Add text to the image&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;download&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/the-simple-image-library-for-php/#download&quot;&gt;Download&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This project is actively maintained on GitHub. Please submit all issues and contributions to the project page. Licensed under the MIT license.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/claviska/SimpleImage&quot;&gt;Download the latest version from GitHub&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;January 10, 2017: SimpleImage 3.0 has been released. Please refer to &lt;a href=&quot;https://github.com/claviska/SimpleImage&quot;&gt;the repo&lt;/a&gt; for API changes and the latest features.&lt;/em&gt;&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>How to delete a tag on GitHub</title>
		<link href="https://www.abeautifulsite.net/posts/how-to-delete-a-tag-on-github/"/>
		<updated>2011-11-16T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/how-to-delete-a-tag-on-github/</id>
		<content type="html">&lt;p&gt;In the world of Git, tags are very useful for keeping track of your project&#39;s version history. A lot of folks will argue that you shouldn&#39;t delete tags, but there are real-world examples in which tags need to be deleted.  That said, it&#39;s both a good and a bad thing that &lt;a href=&quot;http://github.com/&quot;&gt;GitHub&lt;/a&gt; hasn&#39;t built the ability to delete tags into it&#39;s web app.&lt;/p&gt;
&lt;p&gt;It can be frustrating, however, if you ever come across that need.  If you&#39;re one of those individuals, open up a terminal window and navigate to your local Git repository.  Once there, simply run these commands, replacing &lt;strong&gt;[tag]&lt;/strong&gt; with the tag name:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; tag &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;tag&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; push origin :&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;tag&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And if your tag has the same name as one of your branches, use this instead:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; tag &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;tag&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; push origin :refs/tags/&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;tag&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, these steps assume that you have Git running on your local machine.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;August 8, 2016:&lt;/em&gt; GitHub now lets you delete &lt;em&gt;releases&lt;/em&gt; from its website, but this will not delete the tag. As of right now, to delete the actual tag, you still need to use the command line.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Office 2007 files downloading as ZIP files in Internet Explorer</title>
		<link href="https://www.abeautifulsite.net/posts/office-2007-files-downloading-as-zip-in-internet-explorer/"/>
		<updated>2010-03-18T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/office-2007-files-downloading-as-zip-in-internet-explorer/</id>
		<content type="html">&lt;p&gt;Today I learned that Microsoft Office 2007 files (you know, the new ones that end in DOCX, XLSX, and PPTX) don&#39;t always download properly in Internet Explorer. In fact, IE tends to see them as ZIP files and forces their extension to change to &lt;code&gt;.zip&lt;/code&gt; when you select &lt;code&gt;download&lt;/code&gt;. This is because IE is checking for the MIME type instead of blindly going by file extensions. Ironically, since it doesn&#39;t recognize the new Office 2007 files for what they are, IE renames their extensions to &lt;strong&gt;.zip&lt;/strong&gt; upon downloading.&lt;/p&gt;
&lt;p&gt;If you&#39;re wondering why the extensions get changed to &lt;code&gt;.zip&lt;/code&gt;, it&#39;s because the new Office 2007 formats are nothing more than a series of XML documents zipped up with their own special file extensions. Java &lt;code&gt;.jar&lt;/code&gt; files and Mozilla Firefox &lt;code&gt;.xpi&lt;/code&gt; files do mostly the same thing, so this isn&#39;t a new concept, but it does seem to introduce a bit of a problem for Internet Explorer users.&lt;/p&gt;
&lt;p&gt;There seem to be a number of &amp;quot;solutions&amp;quot; out there, but many of them involve telling the end user to change a setting in their browser or something like that — definitely not the best solution. Another option is to simply rename the affected file(s) to the appropriate extension(s) and open them up in Office as usual. Although this works, it&#39;s still not a great solution since most users won&#39;t know to do that.&lt;/p&gt;
&lt;p&gt;The best solution I found was on a &lt;a href=&quot;http://www.webdeveloper.com/forum/showthread.php?threadid=162526&quot;&gt;forum&lt;/a&gt;, where a user suggested setting the MIME types manually on the server. This is obviously a better solution, since end users get the expected behavior and are able to download files with the proper extension. For Apache servers, simply add the following to your config file or create an &lt;code&gt;.htaccess&lt;/code&gt; file in the root directory of your website:&lt;/p&gt;
&lt;pre class=&quot;language-apacheconf&quot;&gt;&lt;code class=&quot;language-apacheconf&quot;&gt;&lt;span class=&quot;token directive-inline property&quot;&gt;AddType&lt;/span&gt; application/vnd.ms-word.document.macroEnabled.12 .docm
&lt;span class=&quot;token directive-inline property&quot;&gt;AddType&lt;/span&gt; application/vnd.openxmlformats-officedocument.wordprocessingml.document docx
&lt;span class=&quot;token directive-inline property&quot;&gt;AddType&lt;/span&gt; application/vnd.openxmlformats-officedocument.wordprocessingml.template dotx
&lt;span class=&quot;token directive-inline property&quot;&gt;AddType&lt;/span&gt; application/vnd.ms-powerpoint.template.macroEnabled.12 potm
&lt;span class=&quot;token directive-inline property&quot;&gt;AddType&lt;/span&gt; application/vnd.openxmlformats-officedocument.presentationml.template potx
&lt;span class=&quot;token directive-inline property&quot;&gt;AddType&lt;/span&gt; application/vnd.ms-powerpoint.addin.macroEnabled.12 ppam
&lt;span class=&quot;token directive-inline property&quot;&gt;AddType&lt;/span&gt; application/vnd.ms-powerpoint.slideshow.macroEnabled.12 ppsm
&lt;span class=&quot;token directive-inline property&quot;&gt;AddType&lt;/span&gt; application/vnd.openxmlformats-officedocument.presentationml.slideshow ppsx
&lt;span class=&quot;token directive-inline property&quot;&gt;AddType&lt;/span&gt; application/vnd.ms-powerpoint.presentation.macroEnabled.12 pptm
&lt;span class=&quot;token directive-inline property&quot;&gt;AddType&lt;/span&gt; application/vnd.openxmlformats-officedocument.presentationml.presentation pptx
&lt;span class=&quot;token directive-inline property&quot;&gt;AddType&lt;/span&gt; application/vnd.ms-excel.addin.macroEnabled.12 xlam
&lt;span class=&quot;token directive-inline property&quot;&gt;AddType&lt;/span&gt; application/vnd.ms-excel.sheet.binary.macroEnabled.12 xlsb
&lt;span class=&quot;token directive-inline property&quot;&gt;AddType&lt;/span&gt; application/vnd.ms-excel.sheet.macroEnabled.12 xlsm
&lt;span class=&quot;token directive-inline property&quot;&gt;AddType&lt;/span&gt; application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx
&lt;span class=&quot;token directive-inline property&quot;&gt;AddType&lt;/span&gt; application/vnd.ms-excel.template.macroEnabled.12 xltm
&lt;span class=&quot;token directive-inline property&quot;&gt;AddType&lt;/span&gt; application/vnd.openxmlformats-officedocument.spreadsheetml.template xltx&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that, if you&#39;re updating your main config file, you&#39;ll have to restart Apache before the changes will take affect. With &lt;code&gt;.htaccess&lt;/code&gt; files you shouldn&#39;t need to restart the server.&lt;/p&gt;
&lt;p&gt;Now your users will be able to download Office 2007 files from your server without any problems.  If you&#39;ve discovered another method for solving this problem, please share it in the comments!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Smoothly scroll to an element without a jQuery plugin</title>
		<link href="https://www.abeautifulsite.net/posts/smoothly-scroll-to-an-element-without-a-jquery-plugin-2/"/>
		<updated>2010-01-22T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/smoothly-scroll-to-an-element-without-a-jquery-plugin-2/</id>
		<content type="html">&lt;p&gt;You know that special effect where you click on a link and your browser smoothly scrolls down to the appropriate section of the page? Pretty slick, right? Here are a couple snippets so you can do the same thing on your own website.&lt;/p&gt;
&lt;h2 id=&quot;scroll-to-a-specific-element&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/smoothly-scroll-to-an-element-without-a-jquery-plugin-2/#scroll-to-a-specific-element&quot;&gt;Scroll to a specific element&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here&#39;s how to programmatically scroll to any &lt;a href=&quot;https://www.abeautifulsite.net/posts/smoothly-scroll-to-an-element-without-a-jquery-plugin-2/test&quot;&gt;element&lt;/a&gt; on the page. If you&#39;re using jQuery, you don&#39;t need a plugin. It&#39;s very simple:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;html, body&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;animate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;scrollTop&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;#target-element&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;top
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will scroll the page down to &lt;code&gt;#target-element&lt;/code&gt; over a period of one second (1,000 milliseconds = 1 second).&lt;/p&gt;
&lt;h2 id=&quot;scroll-to-the-selected-anchor&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/smoothly-scroll-to-an-element-without-a-jquery-plugin-2/#scroll-to-the-selected-anchor&quot;&gt;Scroll to the selected anchor&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You can take things a bit further and animate scrolling for all anchors on your page. The following snippet will watch for clicks on any link that points to an anchor and smoothly scroll down to it:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;a[href^=&quot;#&quot;]&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;click&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; target &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;href&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;preventDefault&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;html, body&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stop&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;animate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;scrollTop&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;top
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;see-it-in-action&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/smoothly-scroll-to-an-element-without-a-jquery-plugin-2/#see-it-in-action&quot;&gt;See it in action&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;See the Pen &lt;a href=&quot;http://codepen.io/claviska/pen/cybdG/&quot;&gt;cybdG&lt;/a&gt; by Cory LaViska (&lt;a href=&quot;http://codepen.io/claviska&quot;&gt;@claviska&lt;/a&gt;) on &lt;a href=&quot;http://codepen.io/&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>The difference between web designers and web developers</title>
		<link href="https://www.abeautifulsite.net/posts/the-difference-between-web-designers-and-web-developers/"/>
		<updated>2009-12-22T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/the-difference-between-web-designers-and-web-developers/</id>
		<content type="html">&lt;p&gt;If you&#39;ve ever worked in, on, with, or around the Internet, you&#39;ve undoubtedly heard the terms &amp;quot;Web Designer&amp;quot; and &amp;quot;Web Developer&amp;quot;.  Oftentimes, the two phrases are used interchangeably by someone who is not familiar with the industry.  Perhaps the concept is irrelevant to a client who just wants to get their website up and running.  Or to a server administrator who has his concerns in the silicon, steel and software that power your website.  And what about the nice lady over in Human Resources who blotches up the job posting during the hiring process?  I mean — designer and developer — they&#39;re the same thing, right?&lt;br /&gt;
Let&#39;s face it, if you have the word &amp;quot;Web&amp;quot; in your euphemism, you&#39;ve probably been hammered with questions from both sides of the playing field.  Designers will hear things like &amp;quot;how can we add a database to the website?&amp;quot;, while developers struggle to answer questions about layout, color selection, image placement, and font styles.&lt;/p&gt;
&lt;p&gt;The truth is, however, that most Web Designers don&#39;t know a thing about Base64 encoding, MIME types, SOAP requests, regular expressions, or SQL injection.  On the flip side, there aren&#39;t a lot of Web Developers that can create visually stunning websites which gloat the type of appeal that Rembrandt himself would appreciate.&lt;/p&gt;
&lt;p&gt;Due to the demanding nature of the industry, it&#39;s all too common to find individuals who are unqualified, inexperienced, or simply not very good at one or the other trying to make their way through a project that requires both creative and technical skills.  This is why many underfunded, poorly planned Web-based projects fail.  Most of the blame can usually be attributed to the fact that not a lot of people actually understand what the difference is between a Web Designer and a Web Developer.  This includes everything from skillsets to the actual role each position plays in the formation of a Web-based project.&lt;/p&gt;
&lt;p&gt;Perhaps the most effective way to differentiate between the two positions is to establish a clear line that separates the roles and responsibilities of each position in the context of a Web-based project.  This will, of course, vary from project to project and from person to person, but we can define a reasonable boundary which the average Web Designer and Web Developer will be comfortable with.&lt;/p&gt;
&lt;h2 id=&quot;what-exactly-is-a-web-designer%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/the-difference-between-web-designers-and-web-developers/#what-exactly-is-a-web-designer%3F&quot;&gt;What exactly is a web designer?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The best Web Designers are of the creative type.  They have a knack for getting inside of their clients&#39; heads and realizing their clients&#39; vision.  They take this vision and masterfully convert it into an aesthetically pleasing, artistic design that aims to impress millions of potential viewers.  Some designers study typography, user interface design, and usability.  Most include tools such as Photoshop, Illustrator, and DreamWeaver in their arsenal and frequent sites such as iStockPhoto, Kuler, and a long list of CSS galleries.&lt;/p&gt;
&lt;p&gt;It is common, albeit arguable, that a designer&#39;s role should also include slicing images, writing (X)HTML, coding CSS, and drafting or editing copy.  For the most part, you can think of a Web Designer as a creative expert.&lt;/p&gt;
&lt;h2 id=&quot;what-exactly-is-a-web-developer%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/the-difference-between-web-designers-and-web-developers/#what-exactly-is-a-web-developer%3F&quot;&gt;What exactly is a web developer?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Web Developers are usually more technical in nature.  They tend to have excellent problem solving skills and are generally good at math.  On a daily basis, a developer will write code in five or more different languages including (X)HTML, CSS, JavaScript, [PHP, ASP, ColdFusion, Ruby, Python, Perl, etc.], and some flavor of SQL.  Web Developers can usually be found wielding some kind of text editor or IDE, an FTP client, three or more web browsers, and development plugins such as Firebug.  They frequent sites similar to the PHP manual, the Mozilla JavaScript reference, and the jQuery Documentation.  A developer also knows what an API is and how to develop with it.&lt;/p&gt;
&lt;p&gt;Although Web Developers are sometimes referred to as programmers, their skills usually exceed those of a conventional software developer.  Think of a Web Developer as more of a technical expert with programming skills.&lt;/p&gt;
&lt;h2 id=&quot;what-about-people-that-do-both%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/the-difference-between-web-designers-and-web-developers/#what-about-people-that-do-both%3F&quot;&gt;What about people that do both?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As suggested earlier, it is actually quite common for Web Designers and Web Developers to be expected to take on tasks that are outside of their personal skillsets.  In my experience, I would only consider a very small number of people that I&#39;ve worked with to be proficient in both design and development.  In most cases, you&#39;ll find a cocky developer that thinks his designs are the greatest thing that ever hit the Internet when, in reality, they&#39;re mediocre at best.  It&#39;s far less common to find a designer who thinks he can code up an entire Web application.&lt;/p&gt;
&lt;h2 id=&quot;so%2C-which-one-should-i-choose%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/the-difference-between-web-designers-and-web-developers/#so%2C-which-one-should-i-choose%3F&quot;&gt;So, which one should i choose?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Which one you choose depends on what exactly you are trying to do, but in many cases your project will require skills from both.  If you&#39;re looking to start a new website or to redesign your old one, you&#39;ll want to look for someone with design talent.  If you&#39;re looking for some kind of database, E-Commerce solution, or integration with another application, you&#39;ll want to look for someone with strong development skills.&lt;/p&gt;
&lt;p&gt;Despite the fact that this writing strives to define the difference between Web Designers and Web Developers, the reality is that you&#39;re bound to find designers who know at least a little bit about development and developers who know at least a little bit about design.  Although both are very different positions which provide entirely different skillsets, the fact of the matter is that most designers and developers have, or will at some point, become factotums — at least to a certain degree.  Some may never bother to differentiate themselves as one or the other.&lt;/p&gt;
&lt;p&gt;Perhaps the most important aspect of managing a Web-based project is being able to determine what skills a particular project requires, and who is the right person for the job.  In this industry it is very clear that, despite a reasonable separation of roles and responsibilities, an individual&#39;s job title is not always a reflection of their personal expertise.  It is, alas, more often an indication of their position in terms of demand and naivety.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>New shortcut keys in Windows 7</title>
		<link href="https://www.abeautifulsite.net/posts/new-shortcut-keys-in-windows-7/"/>
		<updated>2009-11-19T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/new-shortcut-keys-in-windows-7/</id>
		<content type="html">&lt;p&gt;I was happy to learn that Windows 7 has some new shortcut keys that let you control certain aspects of window management right out of the box.  They&#39;re pretty easy to remember too:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Win + Up - Maximize the current window&lt;/li&gt;
&lt;li&gt;Win + Down - Restore a maximized window, otherwise minimize it&lt;/li&gt;
&lt;li&gt;Win + Left - Snap the window to the left side of the screen&lt;/li&gt;
&lt;li&gt;Win + Right - Snap the window to the right side of the screen&lt;/li&gt;
&lt;li&gt;Win + Home - Minimize all except the current window&lt;/li&gt;
&lt;li&gt;Win + Space - Temporarily make all windows transparent&lt;/li&gt;
&lt;li&gt;Win + P - Change the display setting&lt;/li&gt;
&lt;li&gt;Win + T - Move forward through items on the taskbar&lt;/li&gt;
&lt;li&gt;Win + Shift + T - Move backwards through items on the taskbar&lt;/li&gt;
&lt;li&gt;Win + 1 - 9 - Launch or switch to the respective taskbar item (if already open)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you have multiple screen setup (i.e. dual monitors), these will be helpful:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Win + Shift + Left - Move window to the monitor on the left&lt;/li&gt;
&lt;li&gt;Win + Shift + Right - Move window to the monitor on the right&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And, similar to the OS X zoom effect, you can zoom in and out using Win + + and Win + -  respectively. For reference, here are some of the other useful Windows key shortcuts that have been around in earlier version of Windows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Win + D - Show / Hide the desktop&lt;/li&gt;
&lt;li&gt;Win + E - Launch Windows Explorer&lt;/li&gt;
&lt;li&gt;Win + F - Open up a search window&lt;/li&gt;
&lt;li&gt;Win + L - Lock the computer&lt;/li&gt;
&lt;li&gt;Win + M - Minimize all windows&lt;/li&gt;
&lt;li&gt;Win + R - Show the Run dialog&lt;/li&gt;
&lt;li&gt;Win + Pause - Launch the System Properties window&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If there are other useful Windows shortcuts that you find useful, post them in the comments.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Icon Finder: an awesome search engine for icons</title>
		<link href="https://www.abeautifulsite.net/posts/icon-finder-an-awesome-search-engine-for-icons/"/>
		<updated>2009-11-13T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/icon-finder-an-awesome-search-engine-for-icons/</id>
		<content type="html">&lt;p&gt;I came across a &lt;a href=&quot;http://iconfinder.net/&quot;&gt;really awesome icon resource&lt;/a&gt; awhile back, but never got a chance to write anything about it. If you&#39;re a web designer or developer who always has use for quality icons — especially ones with GPL or similar licenses — this is the website for you. It&#39;s essentially a search engine for icons. Everything about this website rocks, especially their logo.&lt;/p&gt;
&lt;p&gt;Not only can you filter by license type and image size, you can also download both the PNG and ICO versions on a black, white, or transparent background. You can edit the tags for any icon and, if after all that you still can&#39;t find the icon that&#39;s right for you, you can opt to purchase a &lt;a href=&quot;http://www.iconfinder.net/custom&quot;&gt;custom icon design&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The website doesn&#39;t have a massive selection of icons to choose from yet, but you should find something relevant to what you&#39;re looking for. If not, you can always design it and &lt;a href=&quot;http://www.iconfinder.net/submit&quot;&gt;submit it yourself&lt;/a&gt;.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>JSNES: a Nintendo emulator built in JavaScript</title>
		<link href="https://www.abeautifulsite.net/posts/jsnes-a-nintendo-emulator-built-in-javascript/"/>
		<updated>2009-11-10T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/jsnes-a-nintendo-emulator-built-in-javascript/</id>
		<content type="html">&lt;p&gt;I remember, not too long ago, arguing with people who said that JavaScript would never be as good as Flash. Granted, at the time many people were afraid of JavaScript and, thus, it wasn&#39;t used as widely as it is today. With the introduction of popular libraries such as &lt;a href=&quot;http://jquery.com/&quot;&gt;jQuery&lt;/a&gt;, &lt;a href=&quot;http://www.prototypejs.org/&quot;&gt;Prototype&lt;/a&gt;, &lt;a href=&quot;http://mootools.net/&quot;&gt;MooTools&lt;/a&gt; and &lt;a href=&quot;http://www.extjs.com/&quot;&gt;many&lt;/a&gt;, &lt;a href=&quot;http://www.dojotoolkit.org/&quot;&gt;many&lt;/a&gt;, &lt;a href=&quot;http://mochikit.com/&quot;&gt;many&lt;/a&gt; others, JavaScript has been on the forefront of the Web 2.0 movement. In fact, it&#39;s rare today to visit a webpage that doesn&#39;t use JavaScript for at least &lt;em&gt;something&lt;/em&gt;. Sure, Flash is still pretty popular, but trends seem to indicate that people are moving further away from it for design and reserving it for &lt;a href=&quot;http://youtube.com/&quot;&gt;videos&lt;/a&gt;, &lt;a href=&quot;http://developer.yahoo.com/yui/uploader/&quot;&gt;file uploaders&lt;/a&gt;, &lt;a href=&quot;http://www.pogo.com/&quot;&gt;online games&lt;/a&gt;, and &lt;a href=&quot;http://aviary.com/&quot;&gt;high level web-based applications&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;So why bother comparing JavaScript to Flash? Everyone knows Flash is better, right?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;And by &lt;em&gt;better&lt;/em&gt;, we can pretty much agree that Flash can do smoother animations, higher level programming, awesome 3D stuff...the list goes on. In fact, you can make an entire website out of pure Flash if you so desire, and it will look exactly the same in every browser. Why use anything else?&lt;/p&gt;
&lt;p&gt;Well, &lt;a href=&quot;http://www.useit.com/alertbox/20001029.html&quot;&gt;Flash has its problems&lt;/a&gt;, and that goes without even mentioning the fact that it&#39;s a closed-source, proprietary technology. (Hint: &lt;a href=&quot;http://en.wikipedia.org/wiki/ECMAScript&quot;&gt;JavaScript &lt;em&gt;isn&#39;t&lt;/em&gt;&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;&lt;em&gt;But still, you can&#39;t do much when it comes to JavaScript. I mean, it&#39;s slow, clunky, and each browser does things just a little bit differently.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Yes, this is very much true. Until now, and even still to some degree, JavaScript remains an emerging technology for more advanced applications such as &lt;a href=&quot;http://sixrevisions.com/javascript/10-impressive-javascript-animation-frameworks/&quot;&gt;animation&lt;/a&gt;, &lt;a href=&quot;http://ui.jquery.com/&quot;&gt;user interface&lt;/a&gt;, and even &lt;a href=&quot;http://www.webresourcesdepot.com/25-amazing-javascript-games-some-fun-and-inspiration/&quot;&gt;games&lt;/a&gt;, but it is by no means primitive. Proof of this lays with JSNES, an 8-bit Nintendo Emulator that was built purely in JavaScript.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/super-mario-bros-3.png&quot; alt=&quot;Screenshot of Super Mario Bros. 3&quot; /&gt;&lt;/p&gt;
&lt;p&gt;If you&#39;re running Internet Explorer right now, don&#39;t bother with the link. You&#39;ll need to switch to &lt;a href=&quot;http://google.com/chrome&quot;&gt;Chrome&lt;/a&gt; if you want to play it at near-normal speed. Even Firefox&#39;s JavaScript engine is too slow, but it&#39;s playable...just really slow.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jsnes.org/&quot;&gt;JSNES&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So there you have it. No, JavaScript isn&#39;t anywhere near Flash in speed or capabilities, but it&#39;s definitely getting there and it&#39;s making plenty of waves in the process.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Table cells and max-widths in Internet Explorer 8</title>
		<link href="https://www.abeautifulsite.net/posts/table-cells-and-max-widths-in-internet-explorer-8/"/>
		<updated>2009-09-30T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/table-cells-and-max-widths-in-internet-explorer-8/</id>
		<content type="html">&lt;p&gt;I recently came across a &lt;a href=&quot;https://connect.microsoft.com/IE/feedback/ViewFeedback.aspx?FeedbackID=425785&quot;&gt;little issue&lt;/a&gt; with Internet Explorer 8 and &lt;code&gt;max-width&lt;/code&gt;. I had an image inside of a table cell and, for some reason, IE8 completely neglected the corresponding CSS &lt;code&gt;max-width&lt;/code&gt; property. The result was the image rendering at full size rather than scaled down to the assigned width, as expected.&lt;/p&gt;
&lt;p&gt;After a &lt;a href=&quot;http://bytes.com/topic/html-css/answers/870359-ie8-display-table-cell-max-width-bug&quot;&gt;little searching&lt;/a&gt;, I found that you can usually resolve this by assigning this to the affected table:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;table-layout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; fixed&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&#39;m not a huge fan of quick-fixes like this, but in the case of a blatent browser bug there isn&#39;t much you can do without going too far out of your way. I&#39;m sure it will be fixed in an IE8 update soon.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Browser makers: where’s the new tab + homepage option?</title>
		<link href="https://www.abeautifulsite.net/posts/browser-makers-wheres-the-new-tab-homepage-option/"/>
		<updated>2009-08-07T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/browser-makers-wheres-the-new-tab-homepage-option/</id>
		<content type="html">&lt;p&gt;Ever since tabbed browsing hit the mainstream I&#39;ve been hooked. It&#39;s rare to see less than a handful of tabs open in my web browser at any time. Whether I&#39;m developing, checking email, or just surfing around, I can never seem to have enough tabs! But there&#39;s one thing about this incredible feature that has really bugged me since Day One — one that seems to have gone completely unnoticed by all of the browser makers to-date.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Why can&#39;t I see my homepage when I open a new tab?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It may seem trivial or silly to complain about, but to me the idea of anything but my homepage opening in a new tab is counterintuitive. For example, if you open a brand new browser window what do you expect to see? Your homepage. If you open any browser (before Safari 4, Opera 9.2, and Google Chrome) what do you expect to see? Your homepage.&lt;/p&gt;
&lt;p&gt;People generally know what to do when they see their homepage because it&#39;s familiar to them. Most of them know how to use the address bar to go to another website. Many of them know how to choose a bookmark to quickly get to their favorite places on the web. For the majority of people, having their homepage open up in a new tab is simply what they subconsciously expect to happen.&lt;/p&gt;
&lt;p&gt;The tragedy here is that this isn&#39;t currently possible in any browser without the use of a &lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/777&quot;&gt;plug-in&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It seems as though browser makers each have their own perspective on what should happen when a new tab is opened. Internet Explorer 8, for example, likes to confuse its users with a mostly empty page to stare at. To spice it up a bit, Microsoft decided to add some infrequently used options that users can click on. How many times have you opened up a new tab because you wanted to &amp;quot;Blog with Windows Live&amp;quot; or &amp;quot;Map [something] with Live Search&amp;quot;? How about &amp;quot;Show copied text&amp;quot;?&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/ie8-new-tab.gif&quot; alt=&quot;New tab view in IE8&quot; /&gt;&lt;/p&gt;
&lt;p&gt;These are clearly not options that are useful to users, but considering how well they promote Microsoft&#39;s services, I can understand how they got there.&lt;/p&gt;
&lt;p&gt;Firefox is my browser of choice for both development and day-to-day browsing, but sadly, it doesn&#39;t do much better than IE when it comes to new tabs. In fact, I think it does even worse in comparison with IE8. It&#39;s a completely blank page.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/firefox-new-tab.gif&quot; alt=&quot;New tab view in Firefox&quot; /&gt;&lt;/p&gt;
&lt;p&gt;If I&#39;m not mistaken, Opera was the first to come out with the &amp;quot;smart page&amp;quot; when they introduced &lt;a href=&quot;http://en.wikipedia.org/wiki/Features_of_the_Opera_web_browser#Speed_Dial&quot;&gt;Speed-Dial&lt;/a&gt; in 9.2. Speed Dial allows users to specify up to nine websites from their bookmarks that will appear in a grid for easy access.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/opera-new-tab.gif&quot; alt=&quot;New tab view in Opera&quot; /&gt;&lt;/p&gt;
&lt;p&gt;It wasn&#39;t long before other browser makers started trying out their own versions of smart pages. Google Chrome made their smart page more useful by adding a search bar, recent bookmarks, and recently closed tabs. As far as smart pages go, this is probably the best of the bunch for functionality, although the nine websites that are automatically chosen aren&#39;t always relevant to your actual use of them.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/chrome-new-tab.gif&quot; alt=&quot;New tab view in Chrome&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Finally, Safari 4 introduced a really slick &amp;quot;Top Sites&amp;quot; smart page that works pretty well. And, as usual with Apple products, it looks great. The only problem is that it&#39;s a little too flashy where it should be more functional. For example, click on the Search History box. The page is instantly replaced by a huge, side-scrolling list of websites. Sure it looks nice at first, but as I search through possible results, I can only see one at a time and it&#39;s very jumpy during transitions. I prefer Firefox&#39;s searchable history over this any day.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/safari-new-tab.gif&quot; alt=&quot;New tab in Safari&quot; /&gt;&lt;/p&gt;
&lt;p&gt;So where do we go from here? Will the world stop because we can&#39;t open new tabs and see our homepages? Of course not. It hasn&#39;t yet, and we&#39;ve been dealing with it for years. But why? To me, this seems like a no-brainer that should have made the top of the list for possible &amp;quot;new tab candidates&amp;quot;. At the very least, I&#39;d like to see the browser makers add this in as an option somewhere.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>What happens if IE8 &quot;breaks&quot; my website?</title>
		<link href="https://www.abeautifulsite.net/posts/what-happens-if-ie8-breaks-my-website/"/>
		<updated>2009-06-27T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/what-happens-if-ie8-breaks-my-website/</id>
		<content type="html">&lt;p&gt;Last year all of the hype was about IE8 and &lt;a href=&quot;http://blogs.msdn.com/ie/archive/2008/01/21/compatibility-and-ie8.aspx&quot;&gt;Microsoft&#39;s decision&lt;/a&gt; to default the browsers version targeting to &amp;quot;quirks mode&amp;quot; rather than standards mode. This essentially meant that developers would have to opt-in to IE8&#39;s standards mode using a proprietary &lt;code&gt;&amp;lt;meta&amp;gt;&lt;/code&gt; tag that tells the browser which mode you want it to render your website in.&lt;/p&gt;
&lt;p&gt;Needless to say, this was a very frustrating proposal for developers worldwide. At the same time, Microsoft&#39;s obligation to not &amp;quot;break&amp;quot; the web was very understandable. It was a catch 22 for the company, but the issue had to be tended to promptly. After much discussion and some encouragement from the community, &lt;a href=&quot;http://www.zeldman.com/2008/03/04/microsoft-reverses-version-targeting-default/&quot;&gt;Microsoft officially reversed their decision&lt;/a&gt; to handle version targeting this way.&lt;/p&gt;
&lt;p&gt;Now that IE8 has been officially released, one problem still remains for many legacy sites. What if IE8 &amp;quot;breaks&amp;quot; your website? The short-term solution is actually &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/cc817574.aspx&quot;&gt;very simple&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Windows Internet Explorer 8 introduces document compatibility modes that allow Web developers to tell the browser to render their pages in the same way as older versions would, thereby allowing the developer to choose when to update.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In short, add this tag inside the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; of each of your webpages and call it a day:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;http-equiv&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;X-UA-Compatible&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;IE=EmulateIE7&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Wait! Don&#39;t actually call it a day and forget about it! Although I&#39;m sure a lot of folks will do just that, the fact is that you really should treat this as the temporary fix that it is and make an honest effort to get those legacy websites and applications up to date. The reality is, however, that many developers will be confronted with compatibility issues as IE8 gets pushed out to millions of users via &lt;a href=&quot;http://www.microsoft.com/windows/downloads/windowsupdate/automaticupdate.mspx&quot;&gt;Windows Automatic Update&lt;/a&gt;. Of course, many won&#39;t have the time or resources it takes to redevelop or modify all those old sites so, in a pinch, you can at least get by.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Images display in Firefox and Safari, but not in Internet Explorer</title>
		<link href="https://www.abeautifulsite.net/posts/images-display-in-firefox-and-safari-but-not-in-internet-explorer/"/>
		<updated>2009-04-24T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/images-display-in-firefox-and-safari-but-not-in-internet-explorer/</id>
		<content type="html">&lt;p&gt;I ran into a little &amp;quot;gotcha&amp;quot; today where an image was displaying properly in Firefox and Safari, but not in Internet Explorer. The weird thing is that it wasn&#39;t showing up as a broken link (no missing image icon with the infamous red &#39;X&#39;). Instead, it wasn&#39;t showing up at all:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As it turns out, if you have the &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes set to an empty string, IE seems to interpret the width and height as zero, which makes the image not appear. All other browsers, of course, seem to discard the empty attributes.&lt;/p&gt;
&lt;p&gt;The solution? Simply remove the empty attributes or plug in the appropriate values.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>PHP functions to get and remove the file extension from a string</title>
		<link href="https://www.abeautifulsite.net/posts/php-functions-to-get-and-remove-the-file-extension-from-a-string/"/>
		<updated>2009-03-12T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/php-functions-to-get-and-remove-the-file-extension-from-a-string/</id>
		<content type="html">&lt;p&gt;I use these regular expressions all the time, but it&#39;s much more convenient to have them both in convenient PHP functions.&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Returns only the file extension (without the dot)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;file_ext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$filename&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;preg_match&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;/&#92;./&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$filename&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;preg_replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;/^.*&#92;./&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$filename&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Returns the file name minus its extension&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;file_ext_strip&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$filename&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;preg_replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;/.[^.]*$/&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$filename&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also use the built-in &lt;a href=&quot;http://php.net/manual/en/function.pathinfo.php&quot;&gt;&lt;code&gt;pathinfo&lt;/code&gt;&lt;/a&gt; function to achieve the same result:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$filename&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;/path/to/file.ext&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;pathinfo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$filename&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;extension&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &quot;ext&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;pathinfo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$filename&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;filename&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &quot;file&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content>
	</entry>
	
	<entry>
		<title>Prevent white noise from appearing in images after fading</title>
		<link href="https://www.abeautifulsite.net/posts/prevent-white-noise-from-appearing-in-images-after-fading/"/>
		<updated>2009-01-10T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/prevent-white-noise-from-appearing-in-images-after-fading/</id>
		<content type="html">&lt;p&gt;The first time I ever saw this alleged bug was in Internet Explorer 7 yesterday. Images were rotating on a page in the form of a slideshow, fading in and out for a nice, smooth transition. One problem, though: in Internet Explorer 7 (and 6, as it turned out), one of the images would appear with a small cluster of white pixels around the black areas.&lt;/p&gt;
&lt;p&gt;To make sure the image wasn&#39;t corrupt, I saved it again using PhotoShop. No luck. Even after saving the image as a GIF instead of a JPEG, the white noise persisted in IE.&lt;/p&gt;
&lt;p&gt;Luckily, some research resulted in finding &lt;a href=&quot;http://www.alexjudd.com/?p=5&quot;&gt;Alex Judd&#39;s post&lt;/a&gt;, which provided a relatively simple solution to the problem.&lt;/p&gt;
&lt;p&gt;To summarize, the white noise occurs in both IE6 and IE7 on some (but not all) images when they fade in or out. This is especially true when you&#39;re using a JavaScript library such as &lt;a href=&quot;http://jquery.com/&quot;&gt;jQuery&lt;/a&gt; or &lt;a href=&quot;http://script.aculo.us/&quot;&gt;script.aculo.us&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Evidently, IE mistakes some of the true-black pixels for transparent pixels, which causes the &amp;quot;white&amp;quot; noise (which may not necessarily be white, depending on the underlying background). One work around, as Alex points out, is to adjust the levels of the image in Photoshop very slightly — just enough to eliminate the true-black pixels.&lt;/p&gt;
&lt;p&gt;To do this, open the image up in PhotoShop and perform the following steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Select &lt;code&gt;Image&lt;/code&gt;, &lt;code&gt;Adjustments&lt;/code&gt;, &lt;code&gt;Levels&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Move the &lt;code&gt;Output Levels&lt;/code&gt; slider a few pixels to the right (or type in a small number, like 5)&lt;/li&gt;
&lt;li&gt;Save the image&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In most cases, there won&#39;t be a noticeable difference in color. Alas, this work around does solve the display problem in IE, but not without tampering with the original image. We&#39;ll have to keep our fingers crossed in that IE8 finally addresses this issue.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>A Beautiful Site becomes &quot;A Beautiful Site, LLC&quot;</title>
		<link href="https://www.abeautifulsite.net/posts/abs-becomes-abs-llc/"/>
		<updated>2008-10-18T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/abs-becomes-abs-llc/</id>
		<content type="html">&lt;p&gt;Today has been an exciting day. I received documentation from the State of Florida stating that A Beautiful Site, LLC. is officially a limited liability company. This marks the new beginning of a period of growth for ABS, which has been, until now, a sole proprietorship.&lt;/p&gt;
&lt;p&gt;In the next few weeks, &lt;a href=&quot;http://www.surrealcms.com/&quot;&gt;Surreal CMS&lt;/a&gt; will be officially released to the public. This is the first of a number of services that ABS will offer, with hopes of making many lives easier through creative, effective, and intuitive Web-based applications.&lt;/p&gt;
&lt;p&gt;To all of our clients, readers, and friends: Thank you for all of your support over the last year and a half. Without your patronage, insight, and encouragement, A Beautiful Site would not be where it is today. I look forward to working with all of you for many years to come.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Import/restore MySQL files from the command line</title>
		<link href="https://www.abeautifulsite.net/posts/import-restore-mysql-files-from-the-command-line/"/>
		<updated>2008-07-24T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/import-restore-mysql-files-from-the-command-line/</id>
		<content type="html">&lt;p&gt;I don&#39;t use this very often, but when I do I always spend a decent amount of time trying to figure it out online. Here are the steps to import a large SQL file from the command line.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Upload the SQL file to the server that your MySQL database is on&lt;/li&gt;
&lt;li&gt;Execute the following command from the terminal (command line):&lt;br /&gt;
&lt;code&gt;mysql -u [username] -p [database name] &amp;lt; /path/to/file/data.sql&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Enter the database password when prompted&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Since anything over about 2MB won&#39;t paste gracefully into a textarea, this works really well with large SQL files generated by &lt;a href=&quot;http://www.phpmyadmin.net/&quot;&gt;phpMyAdmin&lt;/a&gt;. Remember to truncate data and/or drop tables where necessary before importing, otherwise the restore may not work as intended. (For example, &lt;code&gt;CREATE TABLE&lt;/code&gt; will not work if the table already exists and &lt;code&gt;INSERT&lt;/code&gt; statements will fail if a primary key already exists.)&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Parsing a JSON string results in an &#39;Invalid Label&#39; error</title>
		<link href="https://www.abeautifulsite.net/posts/parsing-a-json-string-results-in-an-invalid-label-error/"/>
		<updated>2008-07-17T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/parsing-a-json-string-results-in-an-invalid-label-error/</id>
		<content type="html">&lt;p&gt;Whenever I work with AJAX, jQuery is my preferred JavaScript library and PHP is my preferred server-side language. I use JSON whenever I can to pass data between JavaScript and PHP. After all, &lt;code&gt;$.get&lt;/code&gt; and &lt;code&gt;$.post&lt;/code&gt; both process JSON easily, so it&#39;s my data type of choice.&lt;/p&gt;
&lt;p&gt;Sometimes, however, I can&#39;t rely on &lt;code&gt;$.get&lt;/code&gt; and &lt;code&gt;$.post&lt;/code&gt; to do the dirty work for me. One example is when I&#39;m using a hidden &lt;code&gt;iframe&lt;/code&gt; to upload a file via &amp;quot;AJAX&amp;quot;. To do this, the form posts the file to a server-side script. The script loads in the hidden &lt;code&gt;iframe&lt;/code&gt;, so users don&#39;t see what&#39;s happening behind the scene. Once the upload is complete, the script outputs some information about the file to the &lt;code&gt;iframe&lt;/code&gt; (filename, location, size, etc.). You can then use JavaScript to capture that information.&lt;/p&gt;
&lt;p&gt;For the sake of consistency, my server-side script always outputs a valid JSON string. I rely on this data, which gets scooped out of the &lt;code&gt;iframe&lt;/code&gt;, to tell me if the file got uploaded successfully and, if not, what the error was. If so, I need to know the filename, size, and location. What ends up in the &lt;code&gt;iframe&lt;/code&gt; usually looks something like this:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string-property property&quot;&gt;&quot;filename&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;file.ext&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string-property property&quot;&gt;&quot;size&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;2516582&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string-property property&quot;&gt;&quot;location&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/path/to/file/file.ext&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To parse the JSON string into a JavaScript object, I use &lt;code&gt;eval()&lt;/code&gt;. (Some people prefer to use a &lt;a href=&quot;http://www.json.org/&quot;&gt;JSON parser&lt;/a&gt;, but since the output of the script is controlled, I&#39;ve never found it necessary for this application.) Alas, when JavaScript evaluates the string it results in an &lt;code&gt;invalid label&lt;/code&gt; error.&lt;/p&gt;
&lt;p&gt;The error is the result of &lt;code&gt;eval()&lt;/code&gt; interpreting the first item in the string as a label. This gets me everytime, but it&#39;s extremely easy to fix. Simply wrap the JSON string in parenthesis within &lt;code&gt;eval()&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;eval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;(&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; jsonString &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;)&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is one of those JavaScript &amp;quot;&amp;quot;gotchas&amp;quot;, so I hope I can save people (and myself) a lot of time by documenting it.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>$.postJSON() for jQuery</title>
		<link href="https://www.abeautifulsite.net/posts/postjson-for-jquery/"/>
		<updated>2008-05-31T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/postjson-for-jquery/</id>
		<content type="html">&lt;p&gt;&lt;code&gt;$.getJSON()&lt;/code&gt; is pretty handy for sending an AJAX request and getting back JSON data as a response. Alas, the jQuery documentation lacks a sister function that should be named &lt;code&gt;$.postJSON()&lt;/code&gt;. Why not just use &lt;code&gt;$.getJSON()&lt;/code&gt; and be done with it? Well, perhaps you want to send a large amount of data or, in my case, IE7 just doesn&#39;t want to work properly with a GET request.&lt;/p&gt;
&lt;p&gt;It is true, there is currently no &lt;code&gt;$.postJSON()&lt;/code&gt; method, but you can accomplish the same thing by specifying a fourth parameter (&lt;code&gt;type&lt;/code&gt;) in the &lt;code&gt;$.post()&lt;/code&gt; function:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Send the request&lt;/span&gt;
$&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;script.php&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Do something with the request&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;json&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works for &lt;code&gt;$.get()&lt;/code&gt; as well, which means &lt;code&gt;$.getJSON()&lt;/code&gt; is basically a call to &lt;code&gt;$.get()&lt;/code&gt; with &lt;code&gt;&#39;json&#39;&lt;/code&gt; as the fourth parameter.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Generate random passwords in PHP</title>
		<link href="https://www.abeautifulsite.net/posts/generate-random-passwords-in-php/"/>
		<updated>2008-05-17T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/generate-random-passwords-in-php/</id>
		<content type="html">&lt;p&gt;Here is a function I wrote to generate a random string in PHP. It is probably most useful for generating passwords. You can specify the length of the resulting string, as well as what characters are allowed. The default length is eight and the default character set is alphanumeric.&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;random_string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$length&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$chars&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$chars&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$chars&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;strlen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$s&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$length&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token variable&quot;&gt;$s&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;substr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$chars&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strlen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$chars&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$s&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Usage&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;random_string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content>
	</entry>
	
	<entry>
		<title>Fetching remote web pages with curl and PHP</title>
		<link href="https://www.abeautifulsite.net/posts/fetching-remote-web-pages-with-curl-and-php/"/>
		<updated>2008-04-08T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/fetching-remote-web-pages-with-curl-and-php/</id>
		<content type="html">&lt;p&gt;This is a very brief example of how to use PHP&#39;s &lt;a href=&quot;http://php.net/curl&quot;&gt;curl Library&lt;/a&gt; to retrieve the source of a remote webpage.&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$c&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;curl_init&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;curl_setopt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$c&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;CURLOPT_URL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;http://example.com/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;curl_setopt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$c&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;CURLOPT_RETURNTRANSFER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;$data&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;curl_exec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$c&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;curl_close&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$c&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;CURLOPT_RETURNTRANSFER&lt;/code&gt; is a predefined constant that tells curl to return the output to a variable instead of displaying it in the browser. Visit the &lt;a href=&quot;http://php.net/&quot;&gt;PHP Manual&lt;/a&gt; for a list of all &lt;a href=&quot;http://php.net/manual/en/curl.constants.php&quot;&gt;CURL predefined constants&lt;/a&gt; and their uses.&lt;/p&gt;
&lt;p&gt;The source of the remote file will be stored as a string in &lt;code&gt;$data&lt;/code&gt;.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Determine file extensions using JavaScript</title>
		<link href="https://www.abeautifulsite.net/posts/determine-file-extensions-using-javascript/"/>
		<updated>2008-03-20T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/determine-file-extensions-using-javascript/</id>
		<content type="html">&lt;p&gt;A quick JavaScript function to determine a file&#39;s extension.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fileExt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;substr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;lastIndexOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;.&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content>
	</entry>
	
	<entry>
		<title>But we haven&#39;t even mastered Acid2!</title>
		<link href="https://www.abeautifulsite.net/posts/but-we-havent-even-mastered-acid2/"/>
		<updated>2008-03-06T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/but-we-havent-even-mastered-acid2/</id>
		<content type="html">&lt;p&gt;Safari was the first mainstream browser to pass the &lt;a href=&quot;http://www.webstandards.org/action/acid2/&quot;&gt;Acid2 Test&lt;/a&gt; now. Opera was a close second. Firefox finally nailed it down with version 3. Even Micrsoft, back in December, announced that &lt;a href=&quot;http://blogs.msdn.com/ie/archive/2007/12/19/internet-explorer-8-and-acid2-a-milestone.aspx&quot;&gt;IE8 passes the Acid2 Test&lt;/a&gt;. Web browsers have certainly come a long way towards standards compliance...or have they?&lt;/p&gt;
&lt;p&gt;From the &lt;a href=&quot;http://www.webstandards.org/&quot;&gt;WaSP&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;a href=&quot;http://www.webstandards.org/action/acid3&quot;&gt;Acid3 Test&lt;/a&gt; is designed to test specifications for Web 2.0, and exposes potential flaws in implementations of the public ECMAScript 262 and W3C Document Object Model 2 standards. Collectively known as DOM Scripting, it is these technologies that enable advanced page interactivity and power many advanced web applications such as web-based email and online office applications.&lt;/p&gt;
&lt;p&gt;As a series of 100 mini-tests, Acid3 has already been found to expose flaws in all tested browsers, including Internet Explorer, Firefox, Opera, and Safari. WaSP hopes that Acid3 will prove useful to browser makers during the development of future versions of their products.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Just as no browser properly rendered the Acid2 Test when it was released, no browser currently renders the Acid3 Test properly. Will history repeat itself, or will Opera, Firefox, or maybe even IE8 take the lead and pass the Acid3 test first?&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Netscape support ending in February 2008</title>
		<link href="https://www.abeautifulsite.net/posts/netscape-support-ending-in-february-2008/"/>
		<updated>2008-01-03T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/netscape-support-ending-in-february-2008/</id>
		<content type="html">&lt;p&gt;On December 28th, 2007, the &lt;a href=&quot;http://blog.netscape.com/&quot;&gt;Netscape Blog&lt;/a&gt; announced that AOL is &lt;a href=&quot;http://blog.netscape.com/2007/12/28/end-of-support-for-netscape-web-browsers/&quot;&gt;ending support for Netscape web browsers&lt;/a&gt; effective February 1, 2008. This doesn&#39;t come as much of a surprise, considering the significant decline in Netscape&#39;s marketshare over the past decade to more competative browsers such as IE, Firefox, Opera, and Apple&#39;s Safari. Nevertheless, it is upsetting to see what was once the technical leader among web browsers become a thing of the past.&lt;/p&gt;
&lt;p&gt;Although Netscape has been Mozilla-based since version 6, AOL claims that their &amp;quot;transition into an ad-supported web business leaves little room for the size of investment needed to get the Netscape browser to a point many of its fans expect it to be.&amp;quot; Netscape users are being encouraged to migrate to &lt;a href=&quot;http://firefox.com/&quot;&gt;Mozilla Firefox&lt;/a&gt;. Nostalgic Netscape users can download the &lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/user/56836&quot;&gt;Netscape theme and extensions&lt;/a&gt; for Firefox from the Mozilla website.&lt;/p&gt;
&lt;h2 id=&quot;a-bit-of-history&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/netscape-support-ending-in-february-2008/#a-bit-of-history&quot;&gt;A bit of history&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Netscape Navigator became extremely popular in the mid-1990&#39;s during the consumer Internet revolution. Their success was seen as a threat by Microsoft who promptly responded with Microsoft Internet Explorer. The two companies began an agile battle for marketshare that would eventually be coined the &lt;a href=&quot;http://en.wikipedia.org/wiki/Browser_wars&quot;&gt;Browser Wars&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;During this time, the rival companies implemented a number of proprietary features in an effort to out perform each other and gain marketshare. Consequently, development was focused more on features than on bug fixes, security, and standardization which led to frustrating and confusing times for consumers and developers alike.&lt;/p&gt;
&lt;p&gt;In 1998, as Internet Explorer grew increasingly more popular, Netscape released most of its source code under an open source license which became known as the &lt;a href=&quot;http://www.mozilla.org/&quot;&gt;Mozilla Project&lt;/a&gt;. After being purchased by AOL, Netscape released version 6.0 which was based on the Mozilla browser, but its success was minimal at best. Netscape continued to use the Mozilla framework through 2008, at which time it was officially discontinued.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>IE8 burns the Acid 2 test</title>
		<link href="https://www.abeautifulsite.net/posts/ie8-burns-the-acid-2-test/"/>
		<updated>2007-12-21T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/ie8-burns-the-acid-2-test/</id>
		<content type="html">&lt;p&gt;An internal build of IE8 is reported to have passed the &lt;a href=&quot;http://www.hixie.ch/tests/evil/acid/002/&quot;&gt;Acid 2 test&lt;/a&gt;. This is great news, as Microsoft is showing more and more progress towards incorporating web standards into Internet Explorer, even though IE7 has remained dormant since it&#39;s release back in October 2006.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;http://blogs.msdn.com/ie/archive/2007/12/19/internet-explorer-8-and-acid2-a-milestone.aspx&quot;&gt;entire post&lt;/a&gt; was a breath of fresh air, but I was very impressed by one statement in particular:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;With respect to standards and interoperability, our goal in developing Internet Explorer 8 is to support the right set of standards with excellent implementations and do so without breaking the existing web. This second goal refers to the lessons we learned during IE 7. IE7&#39;s CSS improvements made IE more compliant with some standards and less compatible with some sites on the web as they were coded. Many sites and developers have done special work to work well with IE6, mostly as a result of the evolution of the web and standards since 2001 and the level of support in the various versions of IE that pre-date many standards. We have a responsibility to respect the work that sites have already done to work with IE. We must deliver improved standards support and backwards compatibility so that IE8 (1) continues to work with the billions of pages on the web today that already work in IE6 and IE7 and (2) makes the development of the next billion pages, in an interoperable way, much easier. We&#39;ll blog more, and learn more, about this during the IE8 beta cycle.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A lot of people argue Microsoft&#39;s ability to create a browser that is standards compliant, but the preceding paragraph highlights a few important points. Whether they want to or not, Microsoft has an obligation to make their software backwards compatible. This is understandable to a reasonable degree, especially considering the fact that a significant number of websites would suffer considerably if they didn&#39;&#39;t.&lt;/p&gt;
&lt;p&gt;A Beta version of IE8 is expected to be available in the first half of 2008.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Select all, select none, and invert selection with jQuery</title>
		<link href="https://www.abeautifulsite.net/posts/jquery-checkboxes-select-all-select-none-and-invert-selection/"/>
		<updated>2007-12-09T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/jquery-checkboxes-select-all-select-none-and-invert-selection/</id>
		<content type="html">&lt;p&gt;A demonstration of selecting checkboxes using jQuery.We start off with a bunch of checkboxes:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;fieldset&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;group_1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;checkbox&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;numbers[]&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;checkbox&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;numbers[]&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;checkbox&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;numbers[]&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;checkbox&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;numbers[]&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;3&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;checkbox&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;numbers[]&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;4&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;checkbox&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;numbers[]&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;5&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;checkbox&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;numbers[]&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;6&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;checkbox&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;numbers[]&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;7&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;checkbox&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;numbers[]&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;8&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;checkbox&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;numbers[]&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;9&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;fieldset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we add some links:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;group_1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#select_all&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Select All&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;group_1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#select_none&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Select None&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;group_1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#invert_selection&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Invert Selection&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;rel&lt;/code&gt; attribute is equal to the ID of the containing element of the checkbox group. In this example the containing element is a &lt;code&gt;fieldset&lt;/code&gt;, but it could be a &lt;code&gt;DIV&lt;/code&gt;, &lt;code&gt;P&lt;/code&gt;, &lt;code&gt;UL&lt;/code&gt;, etc.&lt;/p&gt;
&lt;p&gt;Now, we add behaviors using jQuery:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text/javascript&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;
  &lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ready&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Select all&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;a[href=&#39;#select_all&#39;]&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;#&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;rel&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot; input[type=&#39;checkbox&#39;]&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;checked&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Select none&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;a[href=&#39;#select_none&#39;]&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;#&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;rel&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot; input[type=&#39;checkbox&#39;]&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;checked&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Invert selection&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;a[href=&#39;#invert_selection&#39;]&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;#&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;rel&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot; input[type=&#39;checkbox&#39;]&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;checked&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;checked&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To add the same functionality to another group of checkboxes, create more links and adjust the &lt;code&gt;rel&lt;/code&gt; attribute accordingly:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;group_2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#select_all&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Select All&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;group_2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#select_none&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Select None&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;group_2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#invert_selection&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Invert Selection&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;group_3&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#select_all&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Select All&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;group_3&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#select_none&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Select None&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;group_3&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#invert_selection&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Invert Selection&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content>
	</entry>
	
	<entry>
		<title>External popup links using jQuery</title>
		<link href="https://www.abeautifulsite.net/posts/external-popup-links-using-jquery/"/>
		<updated>2007-11-15T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/external-popup-links-using-jquery/</id>
		<content type="html">&lt;p&gt;With the deprecation of the &lt;code&gt;target&lt;/code&gt; attribute in XHTML Strict, opening links in new windows has become a bit trivial, if not annoying, to standardize. I always look for a consistent, unobtrusive approach that degrades gracefully; and since I use jQuery quite frequently, this is how I usually handle them.&lt;/p&gt;
&lt;p&gt;The solution is a small piece of jQuery code in your &lt;code&gt;$(document).ready()&lt;/code&gt; section:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ready&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;click&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;A[rel=&quot;external&quot;]&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;preventDefault&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;href&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, add &lt;code&gt;rel=&amp;quot;external&amp;quot;&lt;/code&gt; to all of the links that you want to open in a new window:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;http://domain.com/&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;external&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Domain.com&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From here on out, users that have JavaScript enabled will receive external pages in new windows, while those without JavaScript will still be directed to the appropriate location.&lt;/p&gt;
&lt;p&gt;I use &lt;code&gt;rel=&amp;quot;external&amp;quot;&lt;/code&gt; because it&#39;s generally a good practice to limit popup links to external websites only. You could very well use &lt;code&gt;rel=&amp;quot;popup&amp;quot;&lt;/code&gt; instead, but I prefer the former for semantics.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Convert arrays to CSV with PHP</title>
		<link href="https://www.abeautifulsite.net/posts/convert-arrays-to-csv-with-php/"/>
		<updated>2007-10-03T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/convert-arrays-to-csv-with-php/</id>
		<content type="html">&lt;p&gt;The following snippet will convert a simple PHP array into CSV (comma-separated values) format.&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;csv&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token variable&quot;&gt;$csv&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$i&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token variable&quot;&gt;$csv&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.=&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&quot;&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;str_replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&quot;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&quot;&quot;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&quot;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$i&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$csv&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.=&lt;/span&gt; &lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;,&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$csv&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;output&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/convert-arrays-to-csv-with-php/#output&quot;&gt;Output&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$a&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;item 1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;item 2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;item 3&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;csv&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &quot;item 1&quot;,&quot;item 2&quot;,&quot;item 3&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content>
	</entry>
	
	<entry>
		<title>Getting proportionally-resized dimensions of an image</title>
		<link href="https://www.abeautifulsite.net/posts/getting-proportionally-resized-dimensions-of-an-image/"/>
		<updated>2007-09-17T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/getting-proportionally-resized-dimensions-of-an-image/</id>
		<content type="html">&lt;p&gt;This is extremely useful when you need to scale down an image within a certain pair of dimensions.&lt;/p&gt;
&lt;h2 id=&quot;get_resized_dimensions()&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/getting-proportionally-resized-dimensions-of-an-image/#get_resized_dimensions()&quot;&gt;get_resized_dimensions()&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;parameters&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/getting-proportionally-resized-dimensions-of-an-image/#parameters&quot;&gt;Parameters&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$width&lt;/code&gt; - The width of the image to be resized&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$height&lt;/code&gt; - The height of the image to be resized&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$max_width&lt;/code&gt; - The maximum allowed width of the resized image&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$max_height&lt;/code&gt; - The maximum allowed height of the resized image&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;return-values&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/getting-proportionally-resized-dimensions-of-an-image/#return-values&quot;&gt;Return values&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The function outputs an array containing two elements: &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$new_dimensions&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;get_resized_dimensions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;640&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;480&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$new_dimensions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;width&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;, &#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$new_dimensions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;height&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The output for the above code will be: &lt;code&gt;200, 150&lt;/code&gt;&lt;/p&gt;
&lt;h3 id=&quot;code&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/getting-proportionally-resized-dimensions-of-an-image/#code&quot;&gt;Code&lt;/a&gt;&lt;/h3&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;get_resized_dimensions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$max_width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$max_height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Check for bad values&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$width&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$height&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token constant boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Determine aspect ratio&lt;/span&gt;
  &lt;span class=&quot;token variable&quot;&gt;$aspect_ratio&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$height&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// First check width&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$width&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$max_width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token variable&quot;&gt;$new_width&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$max_width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token variable&quot;&gt;$new_height&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$new_width&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$aspect_ratio&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token variable&quot;&gt;$new_width&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token variable&quot;&gt;$new_height&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Now check height&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$new_height&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$max_height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token variable&quot;&gt;$new_height&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$max_height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token variable&quot;&gt;$new_width&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$new_height&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$aspect_ratio&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;width&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$new_width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;height&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$new_height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content>
	</entry>
	
	<entry>
		<title>JavaScript functions for basename and dirname</title>
		<link href="https://www.abeautifulsite.net/posts/javascript-functions-for-basename-and-dirname/"/>
		<updated>2007-09-16T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/javascript-functions-for-basename-and-dirname/</id>
		<content type="html">&lt;p&gt;Here are two JavaScript functions that mimic their PHP cousins.&lt;/p&gt;
&lt;h2 id=&quot;basename()&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/javascript-functions-for-basename-and-dirname/#basename()&quot;&gt;basename()&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;basename&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;.*&#92;/&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;dirname()&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/javascript-functions-for-basename-and-dirname/#dirname()&quot;&gt;dirname()&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;dirname&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;.*&#92;/&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unlike their PHP cousins, these functions &lt;em&gt;do not&lt;/em&gt; support paths separated with backslashes.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Avoiding timestamp errors when calculating dates in php</title>
		<link href="https://www.abeautifulsite.net/posts/avoiding-timestamp-errors-when-calculating-dates-in-php/"/>
		<updated>2007-08-29T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/avoiding-timestamp-errors-when-calculating-dates-in-php/</id>
		<content type="html">&lt;p&gt;When calculating dates in PHP, it is easy to add millisecond values such as &lt;code&gt;60 * 60 * 24&lt;/code&gt; to increment the time by one day. This can become problematic for two main reasons.&lt;/p&gt;
&lt;h2 id=&quot;issues-with-leap-years&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/avoiding-timestamp-errors-when-calculating-dates-in-php/#issues-with-leap-years&quot;&gt;Issues with leap years&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A year has approximately 365.25 days, hence a leap year occurs once every four years. If you start on Tuesday April 1, 2003 at 12:00:00 the timestamp would be &lt;code&gt;1049198400&lt;/code&gt;. Adding the length of one day (&lt;code&gt;60 * 60 * 24&lt;/code&gt;, or 86,400ms) would give us &lt;code&gt;1049198400&lt;/code&gt; + 86,400 = &lt;code&gt;1049284800&lt;/code&gt;, which is the same as Wed April 02, 2003 12:00:00. No problem here.&lt;/p&gt;
&lt;p&gt;Using this same methodology, we realize that adding one year (&lt;code&gt;60 * 60 * 24 * 365&lt;/code&gt;, or 31,536,000ms) to Wednesday April 02, 2003 12:00:00 would result in &lt;code&gt;1049284800&lt;/code&gt; + 31,536,000 = &lt;code&gt;1080820800&lt;/code&gt;. This is problematic because &lt;code&gt;1080820800&lt;/code&gt; is the timestamp for Thursday 01 April 2004 12:00:00 (we were expecting the next day, 02 April).&lt;/p&gt;
&lt;p&gt;Even if we used &lt;code&gt;60 * 60 * 24 * 365.25&lt;/code&gt; (or 31,557,600ms) to compensate for the quarter-day phenomenon, we would end up with &lt;code&gt;1049284800&lt;/code&gt; + 31,557,600 = &lt;code&gt;1080842400&lt;/code&gt;, which is Thursday 01 Apr 2004 18:00:00. This &amp;quot;miscalculation&amp;quot; is due to the leap day that occurred on 29 February 2004.&lt;/p&gt;
&lt;h2 id=&quot;issues-with-daylight-saving-time&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/avoiding-timestamp-errors-when-calculating-dates-in-php/#issues-with-daylight-saving-time&quot;&gt;Issues with daylight saving time&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Another issue involves Daylight Saving Time (DST). The calculation is affected similarly and a one hour shift forward or backward will occur if your version of PHP is configured to account for DST. This can turn out to be more drastic than a one hour shift, however. Consider this:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$current_date&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;2007-11-04&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;$timestamp&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strtotime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$current_date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;$timestamp&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// one day increment&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;$new_date&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;Y-m-d&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$timestamp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On 04 November 2007, the time &amp;quot;falls back&amp;quot; one hour, thus &lt;code&gt;$new_date&lt;/code&gt; contains the same value as &lt;code&gt;$current_date&lt;/code&gt; when &lt;code&gt;$current_date&lt;/code&gt; is equal to &lt;code&gt;2007-11-04&lt;/code&gt;. Here are some sample outputs surrounding 04 November 2007:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;$current_date&lt;/th&gt;
      &lt;th&gt;$new_date&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;2007-11-01&lt;/td&gt;
      &lt;td&gt;2007-11-02&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2007-11-02&lt;/td&gt;
      &lt;td&gt;2007-11-03&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2007-11-03&lt;/td&gt;
      &lt;td&gt;2007-11-04&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2007-11-04&lt;/td&gt;
      &lt;td&gt;&lt;mark&gt;2007-11-04&lt;/mark&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2007-11-05&lt;/td&gt;
      &lt;td&gt;2007-11-06&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2007-11-06&lt;/td&gt;
      &lt;td&gt;2007-11-07&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Consequently, if we were outputting hours, minutes and seconds as well, every day after the DST change would be exactly one hour off (until, of course, the next DST change canceled it out).&lt;/p&gt;
&lt;h2 id=&quot;a-better-way-to-calculate-dates&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/avoiding-timestamp-errors-when-calculating-dates-in-php/#a-better-way-to-calculate-dates&quot;&gt;A Better Way to Calculate Dates&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Fortunately, we can overcome both of these hurdles simply by using the &lt;code&gt;strtotime()&lt;/code&gt; function. Instead of adding one day to a timestamp like this:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$date&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can successfully add one day like this:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$date&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strtotime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;Y-m-d&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strtotime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot; +1 day&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Similarly, we can use the same method for weeks, months, years, etc.:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$date&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strtotime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;Y-m-d&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strtotime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot; +1 week&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;$date&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strtotime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;Y-m-d&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strtotime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot; +2 week&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;$date&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strtotime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;Y-m-d&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strtotime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot; +1 month&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;$date&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strtotime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;Y-m-d&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strtotime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot; +30 days&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using the &lt;code&gt;strtotime()&lt;/code&gt; function to add relative blocks of time results in accurate calculations where the previously shown method sometimes fails.&lt;/p&gt;
&lt;p&gt;What if you wanted to add one month to &lt;code&gt;$date&lt;/code&gt;? Using the previous method, you would be forced to estimate the duration of a month or create a really smart algorithm to figure out the exact duration of the given month. Since each month varies in length, the first option is unreliable. The second option has already been incorporated into the &lt;code&gt;strtotime()&lt;/code&gt; function, so why not use that instead?&lt;/p&gt;
&lt;h2 id=&quot;more-examples&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/avoiding-timestamp-errors-when-calculating-dates-in-php/#more-examples&quot;&gt;More examples&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You can use the following examples to experiment with. For further documentation, see the &lt;a href=&quot;http://php.net/&quot;&gt;PHP Manual&lt;/a&gt;&#39;s section on &lt;a href=&quot;http://php.net/strtotime/&quot;&gt;&lt;code&gt;strtotime()&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$date&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;2005-05-10&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;Y-m-d&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strtotime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;Y-m-d&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strtotime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot; +30 days&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// output is 2005-06-09&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;Y-m-d&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strtotime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;Y-m-d&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strtotime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot; +4 weeks&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// output is 2005-06-07&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;Y-m-d&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strtotime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;Y-m-d&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strtotime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot; +1 month&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// output is 2005-06-10&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content>
	</entry>
	
	<entry>
		<title>DaFont: an excellent free font resource</title>
		<link href="https://www.abeautifulsite.net/posts/an-excellent-free-font-resource/"/>
		<updated>2007-07-31T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/an-excellent-free-font-resource/</id>
		<content type="html">&lt;p&gt;I came across an excellent website for free fonts online. No annoying pop-ups, minimal banner ads, and the best feature of all — custom previews for all their fonts.&lt;/p&gt;
&lt;p&gt;Check &#39;em out at &lt;a href=&quot;http://dafont.com/&quot;&gt;dafont.com&lt;/a&gt;.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Forcing file downloads in PHP</title>
		<link href="https://www.abeautifulsite.net/posts/forcing-file-downloads-in-php/"/>
		<updated>2007-07-08T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/forcing-file-downloads-in-php/</id>
		<content type="html">&lt;p&gt;I&#39;ve seen a number of methods to force file downloads using the PHP &lt;code&gt;header()&lt;/code&gt; function which, essentially, sends a raw HTTP header to the browser. Depending on your browser, some files won&#39;t be downloaded automatically. Instead, they will be handled by the browser itself or a corresponding plug-in. This is often an issue with PDF files, TXT files, CSV files, LOG files, multimedia files (MP3, WAV, MOV, MPEG, AVI, etc.), and, for many users, Microsoft Office files. As a developer, being able to force the download of any type of file is extremely useful.&lt;/p&gt;
&lt;h2 id=&quot;to-force%2C-or-not-to-force%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/forcing-file-downloads-in-php/#to-force%2C-or-not-to-force%3F&quot;&gt;To force, or not to force?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The argument of whether or not it is considered &amp;quot;good practice&amp;quot; to force users to download files rather than letting their browser handle them as exepected does not really have a place in this article. In some cases it is appropriate while in others it is probably not.&lt;/p&gt;
&lt;p&gt;It has been a convenience the many times I have used it to push CSV files out to end users who wouldn&#39;t know enough to copy and paste the data from the browser window into a file and then save it.&lt;/p&gt;
&lt;p&gt;It is also handy for when you generate PDF files and want to push them to the user as a download rather than have it open up inside the browser window. Not only does this make the PDF easier for the user to download, it also provides consistency for the way downloads are handled regardless of what browser plug-ins the user has installed.&lt;/p&gt;
&lt;p&gt;Again, in some cases it is appropriate to force a download, in others it is not.&lt;/p&gt;
&lt;h2 id=&quot;the-force-download-script&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/forcing-file-downloads-in-php/#the-force-download-script&quot;&gt;The force download script&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After rigorous browser testing and code tweaking, here is the script I ended up with. All of the unnecessary stuff has been stripped out and it has been simplified as much as possible.&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$file&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;filename.ext&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Quick check to verify that the file exists&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;file_exists&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;die&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;File not found&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Force the download&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;Content-Disposition: attachment; filename=&quot;&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot; . basename(&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$file&lt;/span&gt;&lt;/span&gt;) . &quot;&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;Content-Length: &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;filesize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;Content-Type: application/octet-stream;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;readfile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;using-the-script&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/forcing-file-downloads-in-php/#using-the-script&quot;&gt;Using the script&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Although you can implement this script practically anywhere you want, it is easiest to copy the code into a file named something like &lt;code&gt;force_download.php&lt;/code&gt; and pass an identifier via query string, POST form data, or session variable. Users who are directed to the script will be prompted to download the appropriate file regardless of their browser and plug-in settings.&lt;/p&gt;
&lt;p&gt;The PHP &lt;code&gt;readfile()&lt;/code&gt; function reads files verbatim, including PHP files. This opens up a major security hole if you are passing the actual filename using GET or POST form data (or anything else that the user can spoof). A curious user could easily gain access to sensitive database connection information or other system data by entering something like &lt;code&gt;?file=../includes/db_connection.php&lt;/code&gt;. You should always use some kind of identifier to prevent unauthorized access to sensitive information.&lt;/p&gt;
&lt;h3 id=&quot;compatibility&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/forcing-file-downloads-in-php/#compatibility&quot;&gt;Compatibility&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This script has been tested to work in IE6/7, Firefox 2, Opera 9, and Safari 3.&lt;/p&gt;
&lt;h2 id=&quot;browser-issues&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/forcing-file-downloads-in-php/#browser-issues&quot;&gt;Browser issues&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;safari-%26-filenames&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/forcing-file-downloads-in-php/#safari-%26-filenames&quot;&gt;Safari &amp;amp; filenames&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Surprisingly, all of the force-download scripts I researched online failed to work properly in Safari. The download occurred, but the resulting file was named after the script (i.e. &lt;code&gt;force_download.php&lt;/code&gt;). If I renamed the downloaded file to its correct name, it would open just fine. This, however, was a terrible inconvenience. A bit of testing revealed the culprit. Most of the scripts had a line similar to this:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token function&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;Content-Disposition: attachment&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Others went a step further and had something like this:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token function&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;Content-Disposition: attachment; filename=&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;basename&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But the correct way to specify the filename requires that you put double quotes around the filename attribute:&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token function&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;Content-Disposition: attachment; filename=&quot;&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot; . basename(&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$file&lt;/span&gt;&lt;/span&gt;) . &quot;&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By simply adding quotes around the filename, Safari correctly names the resulting download.&lt;/p&gt;
&lt;h3 id=&quot;caching-problems&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/forcing-file-downloads-in-php/#caching-problems&quot;&gt;Caching problems&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Many of the scripts I found included header calls to tell the browser not to use a cached version of the file. Caching wasn&#39;t an issue with any of the browsers I tested, but if it becomes problematic, add the following lines to the script (above the call to &lt;code&gt;readfile()&lt;/code&gt;).&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token function&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;Cache-Control: no-cache, must-revalidate&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;Expires: Mon, 26 Jul 1997 05:00:00 GMT&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above lines are from the &lt;a href=&quot;http://php.net/header&quot;&gt;PHP Manual&lt;/a&gt; and are expected to work in most browsers.&lt;/p&gt;
&lt;h3 id=&quot;internet-explorer-%26-https&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/forcing-file-downloads-in-php/#internet-explorer-%26-https&quot;&gt;Internet explorer &amp;amp; https&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Certain versions of Internet Explorer will generate the following error message when downloads are forced using this technique:&lt;/p&gt;
&lt;p&gt;Internet Explorer cannot download file from server.  Internet Explorer was not able to open this Internet site. The requested site is either unavailable or cannot be found. Please try again later.&lt;/p&gt;
&lt;p&gt;To get around this, whenever you are forcing a download over HTTPS append the following two lines of code to the force download script (above the call to &lt;code&gt;readfile()&lt;/code&gt;).&lt;/p&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// IE fix (for HTTPS only) header(&#39;Cache-Control: private&#39;);&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;Pragma: private&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can find more information about this bug on the &lt;a href=&quot;http://support.microsoft.com/kb/316431&quot;&gt;MSDN Help &amp;amp; Support&lt;/a&gt; website.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Web standards are just &quot;minor details&quot;</title>
		<link href="https://www.abeautifulsite.net/posts/web-standards-are-just-minor-details/"/>
		<updated>2007-07-02T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/web-standards-are-just-minor-details/</id>
		<content type="html">&lt;p&gt;A friend of mine recently graduated and spread his wings by venturing into the corporate world. He obtained a position as a junior project manager for a web consulting firm in Atlanta. Their work is very professional and their designs are great, but it was immediately evident that they had no understanding of web standards whatsoever. I asked my friend about his company&#39;s stance on the matter.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I asked about that. The sites we build are for industrial use, non-computer people, so we make em work and don&#39;t fuss about the minor details — web standards anyway. We focus on functionality.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;[Jeffrey Zeldman](Jeffrey Zeldman) would pop a blood vessel if he had heard that. After all, isn&#39;t that what web standards is all about? Seems like someone is missing the point here. Mark my word, web companies that worry more about the appearance of their work than the framework that supports it will soon find themselves struggling to keep up with the rest of the world.&lt;/p&gt;
&lt;p&gt;That said, I&#39;d like to recommend a very good book called &lt;a href=&quot;http://www.zeldman.com/dwws/&quot;&gt;Designing With Web Standards&lt;/a&gt;. Whether you want to give a hard-headed employer some insight about the future of the web or you just want to learn a little bit about it yourself, this book will provide you with a complete understanding of what the web was meant to be, and how we&#39;re going to get it there.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;An equal opportunity disease afflicts nearly every site now on the web, from the humblest personal home pages to the multi-million dollar sites of corporate giants. Cunning and insidious, the disease goes largely unrecognized because it is based on industry norms. Although their owners and managers might not know it yet, 99.9% of all websites are obsolete.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Well said, Mr. Zeldman. Well said.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Creating stylesheets for handheld devices</title>
		<link href="https://www.abeautifulsite.net/posts/creating-stylesheets-for-handheld-devices/"/>
		<updated>2007-05-30T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/creating-stylesheets-for-handheld-devices/</id>
		<content type="html">&lt;p&gt;It&#39;s not uncommon so see someone surfing the net with their cell phone or PDA these days or, at least, trying to. Unfortunately, portable technologies still have a long way to go before they conquer the web with their tiny screens. The good news is that, with a little help from stylesheets, your website can look presentable even in the palm of somebody&#39;s hand!&lt;/p&gt;
&lt;h2 id=&quot;handheld-stylesheets&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/creating-stylesheets-for-handheld-devices/#handheld-stylesheets&quot;&gt;Handheld stylesheets&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Similar to the way that &lt;a href=&quot;http://abeautifulsite.net/notebook.php?article=16&quot;&gt;print stylesheets&lt;/a&gt; make your webpages ready for paper, handheld stylesheets make your webpages ready for portable devices. This is often necessary due to the fact that most websites aren&#39;t designed for small screens. Fortunately, with a little extra effort, this obstacle is easy to overcome.&lt;/p&gt;
&lt;h3 id=&quot;linking-the-handheld-stylesheet&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/creating-stylesheets-for-handheld-devices/#linking-the-handheld-stylesheet&quot;&gt;Linking the handheld stylesheet&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We start off by linking to what will become our handheld stylesheet:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;your_handheld_style.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text/css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;media&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;handheld&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice how the &lt;code&gt;media&lt;/code&gt; attribute is set to &lt;code&gt;handheld&lt;/code&gt; instead of &lt;code&gt;screen&lt;/code&gt;.&lt;br /&gt;
Now it&#39;s time to create &lt;code&gt;your_handheld_style.css&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;creating-the-handheld-stylesheet&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/creating-stylesheets-for-handheld-devices/#creating-the-handheld-stylesheet&quot;&gt;Creating the handheld stylesheet&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You could use the normal screen stylesheet as a starting point to make your handheld stylesheet. Depending on the complexity of the CSS, it may be better to start from scratch or just copy and paste one section at a time, modifying the styles little by little and testing as you go. You could even choose to make a completely different look and feel for the handheld version of your website. The key thing to remember here is that you&#39;re creating a design that is meant to display on small screens, often no larger than 240x320 pixels.&lt;/p&gt;
&lt;p&gt;Which ever route you take, the fact that you will eventually need to preview the &amp;quot;portable&amp;quot; version of your website is inescapable...but what if you don&#39;t have a handheld device?&lt;/p&gt;
&lt;h2 id=&quot;testing-the-handheld-stylesheet-without-a-handheld-device&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/creating-stylesheets-for-handheld-devices/#testing-the-handheld-stylesheet-without-a-handheld-device&quot;&gt;Testing the handheld stylesheet without a handheld device&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;using-the-opera-web-browser&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/creating-stylesheets-for-handheld-devices/#using-the-opera-web-browser&quot;&gt;Using the Opera web browser&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There are a lot of features I really love about &lt;a href=&quot;http://www.opera.com/&quot;&gt;Opera&lt;/a&gt;, one of them being the &lt;em&gt;Small screen&lt;/em&gt; feature. By clicking on &lt;code&gt;View&lt;/code&gt; → &lt;code&gt;Small screen&lt;/code&gt; or by pressing &lt;kbd&gt;Shift&lt;/kbd&gt; + &lt;kbd&gt;F11&lt;/kbd&gt;, you can preview any website in a simulated &amp;quot;handheld&amp;quot; mode. This is usually how I test my handheld stylesheets when I don&#39;t have a portable device laying around:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/opera_small_screen.jpg&quot; alt=&quot;Opera small screen&quot; /&gt;&lt;/p&gt;
&lt;p&gt;During testing in &lt;em&gt;Small screen&lt;/em&gt; mode, it may be helpful to add the following code to your stylesheet. This will simulate the screen width of many common portable devices. Just remember to remove it before you upload!&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 240px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; solid 1px #000000&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another thing I would recommend using in your handheld stylesheet is this:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;* { max-width: 100%; }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will prevent elements such as images and textareas from exceeding the width of the device&#39;s screen.&lt;/p&gt;
&lt;h3 id=&quot;using-opera-mini&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/creating-stylesheets-for-handheld-devices/#using-opera-mini&quot;&gt;Using Opera Mini&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Another method to test your handheld stylesheet is with &lt;a href=&quot;http://www.operamini.com/&quot;&gt;Opera Mini&lt;/a&gt;. The program itself requires a mobile phone, but no worries! There&#39;s also an &lt;a href=&quot;http://www.operamini.com/demo/?url=http://abeautifulsite.net&quot;&gt;online simulator&lt;/a&gt; you can try out on any website. Here is what A Beautiful Site looks like on it:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/opera_mini_simulator.jpg&quot; alt=&quot;Opera Mini simulator&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;a-note-about-handheld-stylesheets&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/creating-stylesheets-for-handheld-devices/#a-note-about-handheld-stylesheets&quot;&gt;A note about handheld stylesheets&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;An important thing to remember while you&#39;re coding up a handheld stylesheet is the fact that most handhelds &lt;em&gt;will not&lt;/em&gt; display your site exactly the way you intend them to. It sounds kind of ironic that you just spent the time writing up a completely different stylesheet just to find out that it&#39;s not going to work on the media you intended it to work on. Well, all is not lost. Let me explain...&lt;/p&gt;
&lt;p&gt;Due to hardware and software limitations, most handheld devices are designed to display certain elements of webpages in ways that work for both the device and the user. For example, it wouldn&#39;t be of much use if a PDA with a screen resolution of 240x320 pixels displayed a full-size image that was 800x600 pixels. In most cases, the device will automatically scale the image down so the entire image can be viewed. Similar adjustments are made to text, links, form elements, floated elements, etc.&lt;/p&gt;
&lt;p&gt;So what good is a handheld stylesheet if they aren&#39;t really supported? Well, they provide a foundation for the design which you &lt;em&gt;intend&lt;/em&gt; the portable version of your website to have. Not only that, support for handheld stylesheets is growing rapidly as technology advances. For the little time and effort they actually require to produce, I&#39;d say they&#39;re worth the effort.&lt;/p&gt;
&lt;h2 id=&quot;what-if-i-don&#39;t-have-a-handheld-stylesheet%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/creating-stylesheets-for-handheld-devices/#what-if-i-don&#39;t-have-a-handheld-stylesheet%3F&quot;&gt;What if I don&#39;t have a handheld stylesheet?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A good question indeed. Most portable browsers will either make a good attempt at using your normal stylesheet or ditch the styles altogether. The benefit of using handheld stylesheets is that you are, to some extent, guaranteed your website will reflect at least a little bit of the design which you intended.&lt;/p&gt;
&lt;h2 id=&quot;the-future-of-handheld-stylesheets&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/creating-stylesheets-for-handheld-devices/#the-future-of-handheld-stylesheets&quot;&gt;The future of handheld stylesheets&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Some portable browsers, such as Opera Mini and Apple&#39;s anticipated iPhone version of Safari, do a fairly good job of rendering websites based on their default screen styles. Aside from the low resolutions that portable devices commonly suffer, it makes me wonder if handheld stylesheets will even be necessary in years to come. Since the path is still unclear, however, it can&#39;t really hurt to have them.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Creating a printable website using print stylesheets</title>
		<link href="https://www.abeautifulsite.net/posts/creating-a-printable-website-using-print-stylesheets/"/>
		<updated>2007-05-28T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/creating-a-printable-website-using-print-stylesheets/</id>
		<content type="html">&lt;p&gt;I frequently see little printer icons all over the web that clearly mean I can print out a clean version of the webpage that I&#39;m looking at. These little icons are indeed a beautiful sight from the user&#39;s perspective. No more having to modify printer settings or copy and paste certain content areas into a word processing program just to get it on paper. In fact, I used to be quite the fan of printable versions on the web until I realized what a pain it can be to develop them.&lt;/p&gt;
&lt;p&gt;One method I&#39;ve seen involves creating a separate version of each page that doesn&#39;t have the header, footer, and navigational elements. By doing this, one could nearly double the size of their website without even trying, and who knows how many people are actually going to print all those pages. It seems like a wasted effort, if you ask me.&lt;/p&gt;
&lt;p&gt;A somewhat better method that a lot of database-driven websites use is to create a separate version of the content dynamically. This involves using a special page to generate a printable version of the content, again without the header, footer, and navigational elements. This is a lot better because it doesn&#39;t involve duplicating content on extra, unnecessary webpages. It still requires, however, extra effort to develop that special page to render the printable content; and who&#39;s to say that all the data is coming from just one table in the database? Another potential development nightmare.&lt;/p&gt;
&lt;p&gt;To add insult to injury, both of the aforementioned methods result in the user dealing with an annoying pop-up window or being redirected to the printable version of the page. Oftentimes I thought to myself, &amp;quot;why can&#39;t I just hit CTRL+P and print this?&amp;quot; That would be the ultimate user experience. After all, if nothing else is consistent in web browsers it&#39;s the ability to click on &lt;code&gt;File | Print&lt;/code&gt; to print a webpage. &amp;quot;This has to be possible&amp;quot;, I thought. There must be a way to prevent content from printing like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/no_print_styles_example.jpg&quot; alt=&quot;Example without print styles&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;enter-print-stylesheets&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/creating-a-printable-website-using-print-stylesheets/#enter-print-stylesheets&quot;&gt;Enter print stylesheets&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With the web standards revolution going at full force, more and more people are understanding the need for semantic markup and stylesheets. The benefits are many compared to what little old-fashioned development techniques have to offer. In fact, there are &lt;a href=&quot;http://www.google.com/search?q=the+benefits+of+web+standards&quot;&gt;millions of articles&lt;/a&gt; on the web that outline the very benefits I&#39;m referring to.&lt;/p&gt;
&lt;p&gt;This article will cover one aspect of standard CSS that is becoming more and more popular in everyday development practice: print stylesheets.&lt;/p&gt;
&lt;h2 id=&quot;a-new-way-of-printing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/creating-a-printable-website-using-print-stylesheets/#a-new-way-of-printing&quot;&gt;A new way of printing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When I began developing A Beautiful Site&#39;s Notebook, one of the things I really wanted people to be able to do was print the articles. After all, what good is an article if you can&#39;t print it out and take it with you? Another thing I wanted was for the printouts to look clean and professional, which is what I ultimately achieved. If you don&#39;t believe me, print this page and see for yourself. I think the before &amp;amp; after results are rather convincing:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/print_stylesheets_sample.jpg&quot; alt=&quot;Example with print styles&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Notice how the version without print styles has the website title, navigation menu, and sidebar content cluttering up the first half of the page? In the styled version, these elements are removed and the page almost looks as if it were printed from a word processing program. The font styles and sizes still match that of the original design, with one exception: I decided to style the main text as &lt;code&gt;Times New Roman&lt;/code&gt;, since serif fonts are easier to read on printed media. Most books and magazines use this style of font, so it should give readers a more comfortable feeling when reading the article on paper.&lt;/p&gt;
&lt;p&gt;Note that, compared to the previous examples, the non-styled version of A Beautiful Site&#39;s webpages are still clean and easy to read. One of the benefits of using semantic markup means that, print styles or not, your pages will be more legible when they come out of the printer.&lt;/p&gt;
&lt;h2 id=&quot;minimal-effort&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/creating-a-printable-website-using-print-stylesheets/#minimal-effort&quot;&gt;Minimal effort&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;linking-the-print-stylesheet&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/creating-a-printable-website-using-print-stylesheets/#linking-the-print-stylesheet&quot;&gt;Linking the print stylesheet&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It really doesn&#39;t take much time and effort to apply this technology to your website. In fact, all you need to do is create an additional stylesheet and link each page to it. I typically add this line directly below the normal stylesheet link:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;your_print_style.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text/css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;media&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;print&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice that the &lt;code&gt;media&lt;/code&gt; attribute is set to &lt;code&gt;print&lt;/code&gt; instead of &lt;code&gt;screen&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That was easy, now we need to create &lt;code&gt;your_print_style.css&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;creating-the-print-stylesheet&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/creating-a-printable-website-using-print-stylesheets/#creating-the-print-stylesheet&quot;&gt;Creating the print stylesheet&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You could simply start from scratch and attempt to recreate the entire look and feel of your site in a printable version. Considering the amount of time it would probably take to do this, it seems rather silly to start from the ground up. My technique for creating print stylesheets is much faster and easier.&lt;/p&gt;
&lt;p&gt;First, I copy the normal stylesheet to the new stylesheet. That&#39;s right, &lt;code&gt;select all&lt;/code&gt; → &lt;code&gt;copy&lt;/code&gt; → &lt;code&gt;paste&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Second, I decide which elements I &lt;em&gt;don&#39;t&lt;/em&gt; want to appear on the printed version. For this example, let&#39;s pretend we have the following elements: &lt;code&gt;header&lt;/code&gt;, &lt;code&gt;nav-menu&lt;/code&gt;, &lt;code&gt;sidebar&lt;/code&gt;, &lt;code&gt;content&lt;/code&gt;, and &lt;code&gt;footer&lt;/code&gt;. The only essential element for the printed version will be &lt;code&gt;content&lt;/code&gt;, which contains the information that the user is actually trying to print.&lt;/p&gt;
&lt;p&gt;Next, I disable all of the unnecessary elements from appearing using standard CSS:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;#header,
#nav-menu,
#sidebar,
#footer&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: To avoid confusion, it&#39;s a good idea to delete or comment-out the old CSS that affects these elements.&lt;/p&gt;
&lt;p&gt;The final step is to remove any styles that apply to the &lt;code&gt;content&lt;/code&gt; element that may affect the way it appears in the printed version. This may include paddings, margins, borders, or anything else that hinders the appearance. If you&#39;re using a sans-serif font, you may also wish to style the main text as a serif font, as I did above.&lt;/p&gt;
&lt;h3 id=&quot;the-final-design&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/creating-a-printable-website-using-print-stylesheets/#the-final-design&quot;&gt;The final design&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You can preview your design without having to print it out using the &lt;code&gt;Print Preview&lt;/code&gt; feature in your browser. As with normal stylesheets, feel free to make any adjustments to your print stylesheet to optimize the appearance of the design. Now that you have beautiful, no-hassle, printed versions of your webpages, your users will thank you.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>CSS drop caps</title>
		<link href="https://www.abeautifulsite.net/posts/css-drop-caps/"/>
		<updated>2007-05-23T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/css-drop-caps/</id>
		<content type="html">&lt;p&gt;Traditionally found in printed media, drop caps are created by emphasizing the size, color, weight, or style of the first letter in the first sentence of a paragraph. We can easily reproduce this effect on webpages by using the &lt;code&gt;:first-letter&lt;/code&gt; pseudo element.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/drop-cap-example.png&quot; alt=&quot;Drop cap example&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;writing-the-styles&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/css-drop-caps/#writing-the-styles&quot;&gt;Writing the styles&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let&#39;s start by creating a class called &lt;code&gt;drop-cap&lt;/code&gt; and adding a bit of style to it:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.drop-cap:first-letter&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; left&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 4em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;line-height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; .125em .25em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, the size of the first letter will be significantly larger then the rest of the text. A typical drop cap will line up with the top of the first line of text and the left margin of the paragraph. Horizonal alignment occurs naturally, but we need to account for vertical alignment. By default, it appears slightly higher than we want it to, so the &lt;code&gt;margin-top&lt;/code&gt; attribute offsets it enough to get it in line. Depending on font size and unit, this number will vary.&lt;/p&gt;
&lt;p&gt;You&#39;ll also notice that the &lt;code&gt;first-letter&lt;/code&gt; is floated. This allows the letter to sink into the text instead of remaining inline.&lt;/p&gt;
&lt;h2 id=&quot;applying-the-class&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/css-drop-caps/#applying-the-class&quot;&gt;Applying the class&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that we&#39;ve created the CSS &lt;code&gt;drop-cap&lt;/code&gt; class, it&#39;s easy to apply it to any paragraph element:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;drop-cap&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
  tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
  veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
  commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
  velit esse cillum dolore eu fugiat nulla pariatur.
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which produces something like the image above.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Find and replace hyperlinks and email addresses in PHP</title>
		<link href="https://www.abeautifulsite.net/posts/find-and-replace-hyperlinks-and-email-addresses-in-php/"/>
		<updated>2007-05-15T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/find-and-replace-hyperlinks-and-email-addresses-in-php/</id>
		<content type="html">&lt;p&gt;These two PHP functions use regular expressions to add the appropriate HTML anchor tags around hyperlinks and email addresses in &lt;code&gt;$string&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;php-code&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/find-and-replace-hyperlinks-and-email-addresses-in-php/#php-code&quot;&gt;PHP code&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;language-php&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;parseHyperlinks&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Add  tags around all hyperlinks in $string&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ereg_replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;[[:alpha:]]+://[^&amp;lt;&gt;[:space:]]+[[:alnum:]/]&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;&#92;0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;parseEmails&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Add  tags around all email addresses in $string&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ereg_replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;[_A-Za-z0-9-]+(.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(.[A-Za-z0-9-]+)*(.[A-Za-z]{2,3})&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string double-quoted-string&quot;&gt;&quot;&#92;0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;output&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/find-and-replace-hyperlinks-and-email-addresses-in-php/#output&quot;&gt;Output&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Using &lt;code&gt;parseHyperlinks()&lt;/code&gt;, &lt;code&gt;http://domain.com/index.htm&lt;/code&gt; becomes:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;http://domain.com/index.htm&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;http://domain.com/index.htm&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And using &lt;code&gt;parseEmails()&lt;/code&gt;, &lt;code&gt;email@domain.com&lt;/code&gt; becomes:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;mailto:email@domain.com&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;email@domain.com&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content>
	</entry>
	
	<entry>
		<title>What are favicons?</title>
		<link href="https://www.abeautifulsite.net/posts/what-are-favicons/"/>
		<updated>2007-05-11T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/what-are-favicons/</id>
		<content type="html">&lt;p&gt;A favicon (pronounced &amp;quot;fave-icon&amp;quot;) is a small, iconic image that represents your website. Favicons are most often found in the address bar of your web browser, but they can also be used in lists of bookmarks in web browsers and feed aggregators.&lt;/p&gt;
&lt;p&gt;Well-designed favicons are styled to match the logo or theme of your website, that way users have a quick and easy way to recognize your website at a glance.&lt;/p&gt;
&lt;p&gt;Here is our favicon, displayed in the Firefox address bar:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.abeautifulsite.net/images/favicon_example.png&quot;&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/favicon_example.png&quot; alt=&quot;Example of a favicon&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-type-of-image-is-a-favicon%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/what-are-favicons/#what-type-of-image-is-a-favicon%3F&quot;&gt;What type of image is a favicon?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Although most modern browsers will recognize PNG, GIF, and JPG formats for favicons, Internet Explorer currently does not. It is recommended to use the Microsoft ICO format, which works in all browsers.&lt;/p&gt;
&lt;h2 id=&quot;what-size-should-my-favicon-be%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/what-are-favicons/#what-size-should-my-favicon-be%3F&quot;&gt;What size should my favicon be?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Another good reason to use the ICO format is because it can contain multiple favicons of different sizes in one ICO file. It is best to have, at minimum, a 16x16 pixel version. I usually include 32x32 and 48x48 versions as well. That way, if users drag the bookmark to their desktop they will see a nicely scaled version of the icon instead of the 16x16 version stretched out. To learn how to create a favicon with multiple sizes, see &lt;a href=&quot;https://www.abeautifulsite.net/posts/what-are-favicons/#how-to-create-a-favicon&quot;&gt;How to create a favicon&lt;/a&gt; below.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Below: 16x16, 32x32, and 48x48 versions of A Beautiful Site&#39;s favicon. Each image is embedded in one favicon.ico file.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.abeautifulsite.net/images/favicon_mult_sizes.png&quot;&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/favicon_mult_sizes.png&quot; alt=&quot;A favicon in multiple sizes&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The most common sizes for favicons are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;16x16&lt;/li&gt;
&lt;li&gt;32x32&lt;/li&gt;
&lt;li&gt;48x48&lt;/li&gt;
&lt;li&gt;64x64&lt;/li&gt;
&lt;li&gt;128x128&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;how-to-create-a-favicon&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/what-are-favicons/#how-to-create-a-favicon&quot;&gt;How to create a favicon&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Although there are many ways to create favicons, the easiest is to use an online tool.  We happen to have a &lt;a href=&quot;http://favikon.com/&quot;&gt;favicon generator&lt;/a&gt; that&#39;s entirely free.  It&#39;s called &lt;a href=&quot;http://favikon.com/&quot;&gt;Favikon&lt;/a&gt;.  To create your favicon using Favikon, simply upload an image, crop it, and then download the resulting icon.&lt;/p&gt;
&lt;h2 id=&quot;how-to-link-to-your-favicon&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/what-are-favicons/#how-to-link-to-your-favicon&quot;&gt;How to link to your favicon&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that you&#39;ve created a nice little favicon, you need to tell web browsers and other applications where to find it. Adding this line to the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; section of your HTML will ensure that your favicon will be found:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;shortcut icon&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/favicon.ico&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image/x-icon&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The location of the favicon isn&#39;t really important, as long as the &lt;code&gt;href&lt;/code&gt; attribute is accurate. Most favicons, however, are placed in the root directory (the directory that contains the homepage). Keep in mind that it is not necessary to have multiple instances of the same favicon on one website.&lt;/p&gt;
&lt;p&gt;If you add a favicon without linking to it within your HTML, you may notice that some browsers will still find and display it. This only occurs if the favicon is in the root directory. It isn&#39;t good to rely on this method, so if you want to make sure that applications will see your favicon, &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; to it!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Using JavaScript to prevent comment spam</title>
		<link href="https://www.abeautifulsite.net/posts/using-javascript-to-prevent-comment-spam/"/>
		<updated>2007-05-05T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/using-javascript-to-prevent-comment-spam/</id>
		<content type="html">&lt;p&gt;Comment spam (also known as &#39;link spam&#39;, &#39;blog spam&#39;, and &#39;wikispam&#39;) occurs when people or spam bots post comments on someones blog, guestbook, or wiki for the sole purpose of boosting traffic and promoting better search engine rankings for their site. Like email spam, it can be particularly annoying and troublesome to deal with.&lt;/p&gt;
&lt;h2 id=&quot;common-solutions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/using-javascript-to-prevent-comment-spam/#common-solutions&quot;&gt;Common Solutions&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Many companies and organizations have put forth efforts to prevent comment spam. The well-known search engine &lt;a href=&quot;http://google.com/&quot;&gt;Google&lt;/a&gt;, who owns the popular blog site &lt;a href=&quot;http://blogger.com/&quot;&gt;Blogger&lt;/a&gt;, &lt;a href=&quot;http://googleblog.blogspot.com/2005/01/preventing-comment-spam.html&quot;&gt;announced back in 2005&lt;/a&gt; that it would no longer index anchor tags with the &lt;code&gt;rel=&amp;quot;nofollow&amp;quot;&lt;/code&gt; attribute in them. Web developers were encouraged to make their software automatically add this attribute to all user-contributed hyperlinks. Although this method will discourage a lot of spammers from wasting their time, it doesn&#39;t actually prevent them from posting spam comments.&lt;/p&gt;
&lt;p&gt;Other efforts to combat comment spam focus on the fact that most spammers use automated scripts to submit their messages. These scripts work very much like traditional spam bots but, rather than harvesting email addresses, they target comment forms. Once spammers have a list of comment forms and know the fields that each one asks for, they can use programs like &lt;a href=&quot;http://curl.haxx.se/&quot;&gt;curl&lt;/a&gt; to forge comment submissions. This is an effective way to spam many blogs in a short period of time, so it&#39;s used quite commonly.&lt;/p&gt;
&lt;p&gt;A reasonably good method of preventing this type of spam is called &lt;a href=&quot;http://www.captcha.net/&quot;&gt;CAPTCHA&lt;/a&gt;. CAPTCHA typically displays an image of a word or phrase with obscured lettering that OCR scanners can&#39;t read. This means that, to successfully submit a comment, the user has to provide the correct response to the CAPTCHA test. Since a human is typically required to pass the test, spam bots can&#39;t post bogus comments to sites that use this technology. Unfortunately, this method requires users to take additional steps in order to post comments.&lt;/p&gt;
&lt;p&gt;Of course, you could require that all comments be approved before they are posted, but that requires a lot of extra time and effort, especially for busy sites.&lt;/p&gt;
&lt;h2 id=&quot;a-better-method%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/using-javascript-to-prevent-comment-spam/#a-better-method%3F&quot;&gt;A Better Method?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I&#39;ve decided to share a method that I&#39;ve been using on &lt;a href=&quot;http://laviska.com/&quot;&gt;my personal site&lt;/a&gt; for a few years now. I used to get lots of guestbook and comment spam on a daily basis when my forms were left wide open. Since I&#39;ve applied this technique, I haven&#39;t recieved any comment spam at all. That&#39;s right, &lt;em&gt;not one&lt;/em&gt;. Of course, once I post this there will be nothing stopping spammers from tweaking their bots to work around this solution. At least, for now, it works extremely well.&lt;/p&gt;
&lt;h3 id=&quot;how-it-works&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/using-javascript-to-prevent-comment-spam/#how-it-works&quot;&gt;How it works&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It&#39;s really quite simple. You start with a basic comment form:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;form&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;comment-form&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;add-comment.php&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;post&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  [other input fields here]
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;submit&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Post Comment&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;form&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, to prevent comment spammers, we make a few basic adjustments:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;form&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;comment-form&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;NO-BLOG-SPAM.PHP&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;post&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  [other input fields here]
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Post Comment&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;onclick&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value javascript language-javascript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;submitCommentForm&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;form&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice I changed the form &lt;code&gt;action&lt;/code&gt; to &lt;code&gt;NO-BLOG-SPAM.PHP&lt;/code&gt;. This could be anything, really, as long as it&#39;s not a valid page. Next, I changed the submit button to a regular button and added a JavaScript &lt;code&gt;onclick&lt;/code&gt; event. I&#39;ll show you the &lt;code&gt;submitCommentForm()&lt;/code&gt; function in a minute. First, I want to explain my reasoning for doing all this.&lt;/p&gt;
&lt;p&gt;It makes sense to me to have a bogus &lt;code&gt;action&lt;/code&gt; so that, when a spam bot indexes the form information, it is indexing a submission page that doesn&#39;t exist. If the spammer was trying to use curl to submit the comment, they would receive a &#39;Page Does Not Exist&#39; error.&lt;/p&gt;
&lt;p&gt;It also makes sense to me to change the submit button to a regular button. If the spam bot is trying to submit the form from the within the page, it won&#39;t know which field triggers the submission. In fact, it would have to be smart enough to follow the JavaScript events for every form element that has one (which, in our case, is only one).&lt;/p&gt;
&lt;p&gt;Now, here&#39;s the &lt;code&gt;submitCommentForm()&lt;/code&gt; function. Note that I am including this function from a separate file, which means the spam bot would not only have to be able to follow the JavaScript, but also support including scripts from other parts of the page.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;submitCommentForm&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Change the form action to the real submission page&lt;/span&gt;
  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;comment-form&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;action &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;add-comment.php&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Submit the form&lt;/span&gt;
  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;comment-form&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;submit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, the when the user clicks on the button labeled &#39;Post Comment&#39;, the &lt;code&gt;submitCommentForm()&lt;/code&gt; function is triggered. This changes the form &lt;code&gt;action&lt;/code&gt; to the real submission page, allowing the user&#39;s submission to post. Of course, this still won&#39;t prevent a real human from submitting comment spam, but humans aren&#39;t usually into wasting countless hours of their time typing in comment spam. As I stated before, this method has prevented automated comment spam on my personal site for well over two years.&lt;/p&gt;
&lt;h3 id=&quot;pros&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/using-javascript-to-prevent-comment-spam/#pros&quot;&gt;Pros&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;A lot less comment spam — possibly none&lt;/li&gt;
&lt;li&gt;Users aren&#39;t required to take any extra steps in order to post a comment&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;cons&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/using-javascript-to-prevent-comment-spam/#cons&quot;&gt;Cons&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Requires JavaScript, otherwise users won&#39;t be able to post comments&lt;/li&gt;
&lt;/ul&gt;
</content>
	</entry>
	
	<entry>
		<title>Password protection using .htaccess and .htpasswd</title>
		<link href="https://www.abeautifulsite.net/posts/password-protection-using-htaccess-and-htpasswd/"/>
		<updated>2007-04-29T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/password-protection-using-htaccess-and-htpasswd/</id>
		<content type="html">&lt;p&gt;The simplest way I know to password protect files and directories using Apache&#39;s &lt;code&gt;.htaccess&lt;/code&gt; and &lt;code&gt;.htpasswd&lt;/code&gt; files.&lt;/p&gt;
&lt;h2 id=&quot;.htpasswd&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/password-protection-using-htaccess-and-htpasswd/#.htpasswd&quot;&gt;.htpasswd&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Create a text file with the following text:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;username:password
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The usernames and passwords are stored in this file, one per line, separated by a colon. To allow multiple users:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;firstUser:password
secondUser:password
thirdUser:password
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, for each password, you have to encrypt it using the &lt;code&gt;htpasswd&lt;/code&gt; program (included with Apache). If you don&#39;t have this program, you should be able to find a &lt;a href=&quot;http://www.google.com/search?q=htpasswd+generator&quot;&gt;tool on the web&lt;/a&gt; that can do it. If you have Apache installed on your local system, I strongly recommend using it (You can also generate the entire file with this program, saving you the hassle of creating it in a text editor. Visit &lt;a href=&quot;http://httpd.apache.org/docs/2.0/programs/htpasswd.html&quot;&gt;Apache&#39;s website&lt;/a&gt; to learn how).&lt;/p&gt;
&lt;h3 id=&quot;windows-users&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/password-protection-using-htaccess-and-htpasswd/#windows-users&quot;&gt;Windows users&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Open a command prompt (Start | Run | &lt;a href=&quot;http://command.com/&quot;&gt;command.com&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;type &lt;code&gt;htpasswd -nb username password&lt;/code&gt;, replacing username and password with the appropriate values&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you get an error message, you&#39;ll have to navigate to the directory containing htpasswd.exe (usually Apache[version]bin). If you&#39;re not sure where it is, do a search on your system to find it. Once you&#39;re in the right directory, try the command again.&lt;/p&gt;
&lt;h3 id=&quot;linux-users&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/password-protection-using-htaccess-and-htpasswd/#linux-users&quot;&gt;Linux users&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Open a terminal&lt;/li&gt;
&lt;li&gt;type &lt;code&gt;htpasswd -nb username password&lt;/code&gt;, replacing username and password with the appropriate values&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The program will output something like: &lt;code&gt;username:password&lt;/code&gt;. Copy this into your &lt;code&gt;.htpasswd&lt;/code&gt; file and save it as &lt;code&gt;.htpasswd&lt;/code&gt; (windows users will have to save it as &lt;code&gt;htpasswd.txt&lt;/code&gt; and rename it to &lt;code&gt;.htpasswd&lt;/code&gt; after uploading).&lt;/p&gt;
&lt;h2 id=&quot;.htaccess&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/password-protection-using-htaccess-and-htpasswd/#.htaccess&quot;&gt;.htaccess&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now you&#39;re ready to write your &lt;code&gt;.htaccess&lt;/code&gt; file. This will let Apache know that you want it to use your &lt;code&gt;.htpasswd&lt;/code&gt; file for authentication. You can protect one or more directories and/or files this way. To create your &lt;code&gt;.htaccess&lt;/code&gt; file, create a new text file:&lt;/p&gt;
&lt;h3 id=&quot;protecting-an-entire-directory&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/password-protection-using-htaccess-and-htpasswd/#protecting-an-entire-directory&quot;&gt;Protecting an entire directory&lt;/a&gt;&lt;/h3&gt;
&lt;pre class=&quot;language-apacheconf&quot;&gt;&lt;code class=&quot;language-apacheconf&quot;&gt;&lt;span class=&quot;token directive-inline property&quot;&gt;AuthUserFile&lt;/span&gt; /&lt;span class=&quot;token directive-flags keyword&quot;&gt;[path]&lt;/span&gt;/.htpasswd
&lt;span class=&quot;token directive-inline property&quot;&gt;AuthType&lt;/span&gt; Basic
&lt;span class=&quot;token directive-inline property&quot;&gt;AuthName&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Login to access this folder&quot;&lt;/span&gt;
&lt;span class=&quot;token directive-inline property&quot;&gt;require&lt;/span&gt; valid-user&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;protecting-a-single-file&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/password-protection-using-htaccess-and-htpasswd/#protecting-a-single-file&quot;&gt;Protecting a single file&lt;/a&gt;&lt;/h3&gt;
&lt;pre class=&quot;language-apacheconf&quot;&gt;&lt;code class=&quot;language-apacheconf&quot;&gt;&lt;span class=&quot;token directive-inline property&quot;&gt;AuthUserFile&lt;/span&gt; /&lt;span class=&quot;token directive-flags keyword&quot;&gt;[path]&lt;/span&gt;/.htpasswd
&lt;span class=&quot;token directive-inline property&quot;&gt;AuthType&lt;/span&gt; Basic
&lt;span class=&quot;token directive-inline property&quot;&gt;AuthName&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Login to access this file&quot;&lt;/span&gt;
&lt;span class=&quot;token directive-inline property&quot;&gt;Allow&lt;/span&gt; From All
&lt;span class=&quot;token directive-inline property&quot;&gt;require&lt;/span&gt; valid-user&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;AuthUserFile&lt;/code&gt; is the server location of the &lt;code&gt;.htpasswd&lt;/code&gt; file you have just created. You will need to adjust the path according to your directory structure so that it points to the correct location. &lt;strong&gt;THIS IS VERY IMPORTANT!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Save it as &lt;code&gt;.htaccess&lt;/code&gt; (windows users will have to save it as &lt;code&gt;htaccess.txt&lt;/code&gt; and rename it to &lt;code&gt;.htaccess&lt;/code&gt; after uploading).&lt;/p&gt;
&lt;h2 id=&quot;uploading&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/password-protection-using-htaccess-and-htpasswd/#uploading&quot;&gt;Uploading&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Upload both of the files to the appropriate directories on your webserver. Open a browser and navigate to the respective URL. You should get a login dialog that prompts you for a username and password.&lt;/p&gt;
&lt;h2 id=&quot;troubleshooting&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/password-protection-using-htaccess-and-htpasswd/#troubleshooting&quot;&gt;Troubleshooting&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If the authentication doesn&#39;t work, I would suggest:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Checking the path you set after &lt;code&gt;AuthUserFile&lt;/code&gt;in &lt;code&gt;.htaccess&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Verifying that &lt;code&gt;AllowOverride None&lt;/code&gt;is not present in the section of your Apache config file (usually called httpd.conf) that corresponds to the correct host. In some cases, you may have to specify &lt;code&gt;AllowOverride All&lt;/code&gt; before it will work (even though this is default setting).&lt;/li&gt;
&lt;li&gt;If you used a web-based password encryptor instead of the &lt;code&gt;htpasswd&lt;/code&gt; program, &lt;strong&gt;try another one&lt;/strong&gt;. I found that many would return encrypted strings that Apache could not authenticate for some reason.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Good luck!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>GIF, JPEG or PNG? Using images on the web</title>
		<link href="https://www.abeautifulsite.net/posts/gif-jpeg-or-png-using-images-on-the-web/"/>
		<updated>2007-04-29T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/gif-jpeg-or-png-using-images-on-the-web/</id>
		<content type="html">&lt;p&gt;This article aims to describe the difference between the three most popular types of images used on the Web, and how to use them effectively in your websites.&lt;/p&gt;
&lt;h2 id=&quot;jpeg&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/gif-jpeg-or-png-using-images-on-the-web/#jpeg&quot;&gt;JPEG&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;JPEG files are compressed images that maintain a balance of size versus quality. For example: &lt;em&gt;More compression = less image quality = smaller file size&lt;/em&gt;. In contrast, &lt;em&gt;less compression = more image quality = larger file size&lt;/em&gt;. Since JPEG files do not maintain 100% of the original image&#39;s pixel data, it is not considered a lossless image format.&lt;/p&gt;
&lt;h3 id=&quot;usage&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/gif-jpeg-or-png-using-images-on-the-web/#usage&quot;&gt;Usage&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Due to this sensitive balance, JPEGs are best suited for photographs where slightly depreciated quality is not very noticeable. JPEG is not typically a good format for logos, icons, and other simple images.&lt;/p&gt;
&lt;h2 id=&quot;gif&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/gif-jpeg-or-png-using-images-on-the-web/#gif&quot;&gt;GIF&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The GIF format was developed by CompuServe specifically for use online. GIF, sometimes pronounced &amp;quot;GIFF&amp;quot;, is a lossless, 8-bit image format. Lossless means that 100% of the original pixel data is maintained. The term 8-bit refers to color depth — an 8-bit image can only have up to 256 colors.&lt;/p&gt;
&lt;h3 id=&quot;usage-1&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/gif-jpeg-or-png-using-images-on-the-web/#usage-1&quot;&gt;Usage&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Because of these limitations, GIFs &lt;em&gt;should not&lt;/em&gt; be used for photographic images. Instead, use them for things like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Logos&lt;/li&gt;
&lt;li&gt;Icons&lt;/li&gt;
&lt;li&gt;Layout images (such as corners, borders, etc.)&lt;/li&gt;
&lt;li&gt;Any other small, simple image with only a few colors&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;transparency&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/gif-jpeg-or-png-using-images-on-the-web/#transparency&quot;&gt;Transparency&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;GIF supports basic transparency, which means that certain pixels in the image can be &amp;quot;invisible&amp;quot;, so you can see whatever lies behind them. This is especially useful for making icons that are intended to sit on top of a varying background.&lt;/p&gt;
&lt;h3 id=&quot;compression&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/gif-jpeg-or-png-using-images-on-the-web/#compression&quot;&gt;Compression&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The GIF format uses the LZW compression algorithm, which is patented by Unisys. For a time, this meant that the authors of image-editing programs were forced to pay Unisys for the rights to include GIF support in their programs. The patent, however, expired on June 20, 2003 in the United States.&lt;/p&gt;
&lt;h3 id=&quot;interlacing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/gif-jpeg-or-png-using-images-on-the-web/#interlacing&quot;&gt;Interlacing&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;GIF also supports interlacing, which makes the image appear to load faster in web browsers. This could be helpful for people browsing your site on a slow dial-up connection.&lt;/p&gt;
&lt;h3 id=&quot;animated-gifs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/gif-jpeg-or-png-using-images-on-the-web/#animated-gifs&quot;&gt;Animated GIFs&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;An animated GIF is a single file that contains multiple variations (frames) of an image. These frames are drawn over and over again to create the illusion of animation. When used appropriately, animated GIFs can be catchy and impressive. Unfortunately, many people tend to overuse them on the web, creating a very annoying experience for their users.&lt;/p&gt;
&lt;h2 id=&quot;png&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/gif-jpeg-or-png-using-images-on-the-web/#png&quot;&gt;PNG&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;PNG files, pronounced &amp;quot;PING&amp;quot;, were developed as a freeware alternative to GIF files which, at the time, used a patented compression algorithm. The PNG format is also lossless but, unlike GIF, PNG can support 8-bit and 24-bit images.&lt;/p&gt;
&lt;h3 id=&quot;8-bit-pngs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/gif-jpeg-or-png-using-images-on-the-web/#8-bit-pngs&quot;&gt;8-bit PNGs&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;An 8-bit PNG can have up to 256-colors with basic transparency. This format is very similar to that of GIFs, except for the compression method.&lt;/p&gt;
&lt;h3 id=&quot;usage-2&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/gif-jpeg-or-png-using-images-on-the-web/#usage-2&quot;&gt;Usage&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;8-bit PNGs should be used the same way as GIFs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Logos&lt;/li&gt;
&lt;li&gt;Icons&lt;/li&gt;
&lt;li&gt;Layout images (such as corners, borders, etc.)&lt;/li&gt;
&lt;li&gt;Any other small, simple image with only a few colors&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;24-bit-pngs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/gif-jpeg-or-png-using-images-on-the-web/#24-bit-pngs&quot;&gt;24-bit PNGs&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;24-bit PNGs can have up to 16 million colors and can support alpha-transparency. This means that a partially transparent image with anti-aliasing can blend smoothly into the background.&lt;/p&gt;
&lt;h3 id=&quot;png-support&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/gif-jpeg-or-png-using-images-on-the-web/#png-support&quot;&gt;PNG support&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;PNG support is becoming more widespread as browser developers become more conscious of &lt;a href=&quot;http://www.w3.org/&quot;&gt;Web Standards&lt;/a&gt;. Fortunately, PNGs are currently supported by all popular web browsers including, IE*, Firefox, Safari, Opera, and Konqueror.&lt;/p&gt;
&lt;p&gt;*Unfortunately, IE6 messes up alpha-transparency in 24-bit PNGs and displays a grayish-blue background color instead. IE6 has also been known to render some 8-bit PNG colors slightly off-hue (a gamma correction error). Although the alpha-transparency issue has been resolved in IE7 beta 2, Microsoft hasn&#39;t addressed gamma correction yet.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Business cards</title>
		<link href="https://www.abeautifulsite.net/posts/business-cards/"/>
		<updated>2007-04-29T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/business-cards/</id>
		<content type="html">&lt;p&gt;&lt;a href=&quot;http://vistaprint.com/&quot;&gt;VistaPrint&lt;/a&gt; delivered 1,000 “A Beautiful Site” business cards the other day, and I couldn&#39;t resist playing with them.&lt;/p&gt;
&lt;p&gt;I decided to go conservative with the design, relying a bit on curiosity to draw attention to the business. Nevertheless, I am pleased with the way they turned out.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/abs-original-business-cards.jpg&quot; alt=&quot;A number of business cards layed out in a circle&quot; /&gt;&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>An Event Apart, Boston</title>
		<link href="https://www.abeautifulsite.net/posts/an-event-apart-boston/"/>
		<updated>2007-04-29T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/an-event-apart-boston/</id>
		<content type="html">&lt;p&gt;The plane took off from Orlando as I sat half asleep in my seat. With my laptop at my feet, I wondered what kind of intriguing things I would learn at the web conference I had signed up for. I anticipated this day for months now and it was finally here. I was on my way to &lt;a href=&quot;http://aneventapart.com/&quot;&gt;An Event Apart&lt;/a&gt;, Boston. Wow!&lt;/p&gt;
&lt;p&gt;I have always been an avid reader of &lt;a href=&quot;http://alistapart.com/&quot;&gt;A List Apart&lt;/a&gt;. They never fail to produce really great articles in regards to every aspect of web design. When I first saw an advertisement for An Event Apart online, I was stoked. I gathered all the information possible and practically begged my employer to fund the trip. A few weeks later, it was said and done. On March 26th and 27th I was in Boston listening to some of the web&#39;s greatest voices. It was awesome. No, that&#39;s an understatement. It was incredible!&lt;/p&gt;
&lt;h2 id=&quot;the-hotel&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/an-event-apart-boston/#the-hotel&quot;&gt;The hotel&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The conference was held at the &lt;a href=&quot;http://marriott.com/hotels/travel/bosco-boston-marriott-copley-place/&quot;&gt;Marriott Copley Place&lt;/a&gt;, where I stayed on the 33rd floor. The rooms were very nice, the food services were excellent, and the location was perfect — walking distance to anything you could possibly need and a Shaw&#39;s 24-hour supermarket across the street. Nice.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/aea-badge.jpg&quot; alt=&quot;A picture of my conference badge&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/aea-sign.jpg&quot; alt=&quot;Me in front of the An Event Apart sign before the conference&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;day-1&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/an-event-apart-boston/#day-1&quot;&gt;Day 1&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;On the first day I got to put some familiar names with faces. Specifically Jeffrey Zeldman (&lt;a href=&quot;http://zeldman.com/&quot;&gt;zeldman.com&lt;/a&gt;), Eric Meyer (&lt;a href=&quot;http://meyerweb.com/&quot;&gt;meyerweb.com&lt;/a&gt;), and Dan Cederholm (&lt;a href=&quot;http://simplebits.com/&quot;&gt;simplebits.com&lt;/a&gt;). Other speakers who spoke that day were Jason Santa Maria (&lt;a href=&quot;http://jasonsantamaria.com/&quot;&gt;jasonsantamaria.com&lt;/a&gt;) on design, Steve Krug (&lt;a href=&quot;http://sensible.com/&quot;&gt;sensible.com&lt;/a&gt;) on usability, and Andrew Kirkpatrick (Adobe) on accessibility.&lt;/p&gt;
&lt;p&gt;Lunch was sponsored by Adobe and the opening night party was sponsored by Media Temple at Restaurant 33. I hear everyone had a killer time, but due to a stomach bug I wasn&#39;t able to attend the party. ~ sigh ~&lt;/p&gt;
&lt;p&gt;I did get a chance to speak with Dan Cederholm, however. He signed my copy of Bulletproof Web Design and we talked briefly about running a web design business. Dan&#39;s a great guy. His willingness to talk with you and his attitude towards those who are interested in the web really impressed me. I hope I have an opportunity to meet with him again in the future.&lt;/p&gt;
&lt;h2 id=&quot;day-2&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/an-event-apart-boston/#day-2&quot;&gt;Day 2&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;On the second day I got to meet Molly E. Holzshlag (&lt;a href=&quot;http://molly.com/&quot;&gt;molly.com&lt;/a&gt;), who has authored over 30-something books about the the web and currently works for Microsoft. Specifically, on the IE7 team. Her speech was entitled, &amp;quot;Building Better Browsers&amp;quot;. After she spoke, I had a chance to meet with her one-on-one for a while. We talked about some of the issues that Microsoft had to face to get IE7 up to speed with the web standards movement. In a nutshell, I&#39;m happy to say that my opinion of Microsoft&#39;s recent efforts to improve IE7 has changed for the better. She also assured me that gamma corrections in PNGs is &amp;quot;on the way&amp;quot;. That put a smile on my face.&lt;/p&gt;
&lt;p&gt;Other speakers on Day 2 included Cameron Moll (&lt;a href=&quot;http://cameronmoll.com/&quot;&gt;cameronmoll.com&lt;/a&gt;) on design, Ethan Marcotte (&lt;a href=&quot;http://sidesh0w.com/&quot;&gt;sidesh0w.com&lt;/a&gt;) on web standards, Eric Meyer on CSS and IE7, and Jeffrey Zeldman on selling design.&lt;/p&gt;
&lt;p&gt;We wrapped up the second day with critiques. A lot of people submitted websites to be critiqued by the speakers, but only a handful were chosen to be reviewed. I didn&#39;t submit a site for this...I don&#39;t know why.&lt;/p&gt;
&lt;h2 id=&quot;afterthoughts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;direct-link&quot; href=&quot;https://www.abeautifulsite.net/posts/an-event-apart-boston/#afterthoughts&quot;&gt;Afterthoughts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;An Avent Apart was an experience I won&#39;t soon forget. It was worth every penny (even if I had paid for it out of my own pocket). Next time, I think it would be good to see a bit more on design and possibly some hands-on activities. I really liked having the opportunity to meet some of the speakers in person. It was also nice to find out that my understanding of good web practice was on par with the rest of the world.&lt;/p&gt;
&lt;p&gt;A special thanks goes out to all the speakers from An Event Apart, Boston.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>A Beautiful Site launched</title>
		<link href="https://www.abeautifulsite.net/posts/a-beautiful-site-launched/"/>
		<updated>2007-04-29T00:00:00Z</updated>
		<id>https://www.abeautifulsite.net/posts/a-beautiful-site-launched/</id>
		<content type="html">&lt;p&gt;I&#39;d like to introduce my new web design studio. After considering a list of potential names and designs, I finally came up with a name that I thought fitting for the kind of web design business that I want to run.&lt;/p&gt;
&lt;p&gt;After a few pencil and paper sketches, a few hours in Photoshop, and a couple of late nights staring into two LCD monitors, A Beautiful Site was born.&lt;br /&gt;
A Beautiful Site is built on a foundation of web standards, user-oriented design, and excellent development practices. These values follow through from the first keystroke to the final pixel. Pride is something that comes at no extra cost to our customers, and that&#39;s guaranteed.&lt;/p&gt;
&lt;p&gt;So please feel free to look around. Read some articles, send us a message, or tell a friend about us. I can&#39;t wait to hear from you!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Update: It&#39;s been awhile since this website first launched and things have changed quite a bit. Here&#39;s a glimpse of the original design from 2007.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.abeautifulsite.net/images/abs-original-website.png&quot; alt=&quot;A vintage screenshot of the original website&quot; /&gt;&lt;/p&gt;
</content>
	</entry>
</feed>
