Write Your Media Queries in Pixels, Not EMs

In all of my latest projects, I was using em units for writing media queries, just like so:

@media (min-width: 30em) {
	/* CSS for viewports >= 480px */
}

I had switched to em units some time ago because writing pixel-based media queries seemed to be the inferior solution. At first, because browsers used to handle zooming really bad, like Lyza Gardner had shown in 2012 in her article The EMs have it: Proportional Media Queries FTW!. And although the zooming behavior has since been made consistent, another article made a strong case against using pixels for media queries: Zell Liew showed in a couple of Codepen experiments that although most browsers handled pixel-based media consistently, Safari was the party pooper that still didn’t handle pixel-based media queries properly.

But yesterday, I stumbled upon an article by Alastair Campbell‏ in which he states that the advice to not use pixels in media queries should be considered a myth. I got curious: Maybe the Safari bug from back then had been resolved in the meantime and using pixel-based media queries was safe now?

So I looked at Zell Liew's article again and tried to find the Codepen he had used. I could not find it but found one further down in the comments. It was by a user named Ola who repeatedly pointed out that Safari was indeed handling media queries in the wrong way – but contrary to what the article suggested, not the ones that used pixels were problematic, but the em and rem media queries.

So I looked into it and it indeed seems like he is right. Safari handles pixel-based media queries correctly when the user zooms. If, for example, the zoom level is at 125 %, a min-width:400px media query correctly “fires” at a width of 500 device pixels.

You can try it out yourself. Open this Codepen in Safari and change the zoom level to 125 %. Then change the width of the browser window until the media queries kick in. And while the pixel-based behaves correctly, the em-based media query is triggered at a width of 625 device pixels. Obviously, Safari multiplies the font-size as well as the value in the media query by 1.25:

16px * 1.25 * 25 * 1.25 = 625px

Alternatively, look at this test page with Safari and zoom in/out (and compare it to any other browser): http://output.jsbin.com/ubuvay/4. There's also a related Webkit bug report (41063).

So until this issue gets resolved, it seems like we have to change the recommendation regarding media queries once more: For the most consistent cross-browser behavior, write your media queries in pixels, not ems.

What do you think? Am I missing something here, maybe? And how do you write your media queries? If you write an answer and link back to this article, you can add it via the form below and it will appear in the Webmentions section. But you can also write via Twitter or email, of course. I'd be very happy to hear your opinion.

Colorful Code: Adding Syntax Highlighting to My Site

In all of the posts I published on my site so far, I’ve never shared a single line of code. But since this is going to change with the next article on pattern libraries, I spent a little time over the weekend implementing syntax highlighting for my posts. I settled on Lea Verou’s Prism, a lightweight, extensible syntax highlighter for the Web. It is used by sites like Smashing Magazine, A List Apart, or CSS-Tricks and it is dead simple to use. Just include prism.js and wrap your code in <pre><code> tags and Prism does the rest for you. The styling is done through CSS, so it is up to you if you want use one of the many ready-made themes or prefer to write your own styles. I decided on the latter as it promised to be fun and I wanted to see how theming is done for syntax highlighting.

The resulting theme is loosely based on GitHub’s styles so that it feels familiar, but it aims to be a little bit more intensively colored without being too colorful because the main goal of syntax highlighting is to improve the readability of code. So below you will find some examples of Prism in action. Feel free to write me if you have any remarks or questions.

<!-- HTML / Handlebars -->

<form class="webmention-form" method="post" action="/{{ craft.webmention.settings.endpointSlug }}">
	<label for="webmention-source">Have you published a response to this? Send me a <a href="http://indiewebcamp.com/webmention">webmention</a> by letting me know the <abbr title="Uniform Resource Locator">URL</abbr>.</label>
	<input type="url" name="source" id="webmention-source" placeholder="URL / permalink of your article">
	<input type="hidden" name="target" value="{{url}}">
	<button type="submit">Ping!</button>
</form>
/* CSS / Sass */

// Variable
$primary-color: hotpink;

// Mixin
@mixin border-radius($radius) {
    -webkit-border-radius: $radius;
    -moz-border-radius: $radius;
    border-radius: $radius;
}

.my-element {
    color: $primary-color;
    width: 100%;
    overflow: hidden;
}

.my-other-element + .my-element:first-child {
    @include border-radius(5px);
}
/* JavaScript */

/* MIT license http://www.opensource.org/licenses/mit-license.php/
 * @author Lea Verou http://lea.verou.me
 */

var Prism = (function(){

// Private helper vars
var lang = /\blang(?:uage)?-(\w+)\b/i;
var uniqueId = 0;

var _ = _self.Prism = {
	manual: _self.Prism && _self.Prism.manual,
	util: {
		encode: function (tokens) {
			if (tokens instanceof Token) {
				return new Token(tokens.type, _.util.encode(tokens.content), tokens.alias);
			} else if (_.util.type(tokens) === 'Array') {
				return tokens.map(_.util.encode);
			} else {
				return tokens.replace(/&/g, '&').replace(/<\/g, '<').replace(/\u00a0/g, ' ');
			}
		},

		type: function (o) {
			return Object.prototype.toString.call(o).match(/\[object (\w+)\]/)[1];
		},

		objId: function (obj) {
			if (!obj['__id']) {
				Object.defineProperty(obj, '__id', { value: ++uniqueId });
			}
			return obj['__id'];
		},

		// Deep clone a language definition (e.g. to extend it)
		clone: function (o) {
			var type = _.util.type(o);

			switch (type) {
				case 'Object':
					var clone = {};

					for (var key in o) {
						if (o.hasOwnProperty(key)) {
							clone[key] = _.util.clone(o[key]);
						}
					}

					return clone;

				case 'Array':
					// Check for existence for IE8
					return o.map && o.map(function(v) { return _.util.clone(v); });
			}

			return o;
		}
	}
}
/* PHP */

class WebmentionPlugin extends BasePlugin
{   
    function init() 
    {
        // Require dependencies (composer)
        require CRAFT_PLUGINS_PATH.'/webmention/vendor/autoload.php';
        craft()->on('entries.saveEntry', function(Event $event) {
            craft()->webmention->onSaveEntry($event);
        });
        # sections.onDeleteSection
        craft()->on('sections.onDeleteSection', function(Event $event) {
            craft()->webmention->syncEntryTypes();
        });
        # sections.onSaveSection
        craft()->on('sections.onSaveSection', function(Event $event) {
            craft()->webmention->syncEntryTypes();
        });
        # sections.onSaveEntryType
        craft()->on('sections.onSaveEntryType', function(Event $event) {
            craft()->webmention->syncEntryTypes();
        });
    }
    public function getName()
    {
         return Craft::t('Webmention');
    }
    public function getVersion()
    {
        return '0.3.1';
    }
}

We Are Team Internet. We Need to Save #NetNeutrality.

Once more, net neutrality is under attack. This founding principle of the open web guarantees that all data packages are treated equally – regardless of content or the amount of money you pay your service provider. Net neutrality keeps the internet open and uncensored and by that fosters freedom of speech and an exchange of ideas.

Today, 12 July, is the internet-wide day of action to save net neutrality. And we all have a voice and a responsibility to stop this threat to the open web.

So join the protest by adding an alert to your site, change your avatar, spread the word on social media, or do what you do best to fight for net neutrality. To learn more, visit battleforthenet.com or read more about why the 12 July protest to protect net neutrality matters.

We need to stop this together. We are team internet.

Thanks to @webrocker for the reminder!

Adding JSON Feed to My Craft CMS Site

Despite the proclaimed death of RSS I know a lot of people who still love to read their feeds on a daily basis. So feeds are definitely here to stay and providing your readers with different ways of consuming your content is also an important part of a website, especially if you consider yourself (and your site) part of the open web.

Recently, Manton Reece and Brent Simmons announced an interesting new feed format called JSON Feed. As its name implies, JSON Feed is similar to RSS or Atom, but it uses JSON as the format for syndication. This has some advantages over XML, for example that it is far easier to read and write. Manton and Brent also have the hope that the lightness, simplicity, and flexibility of JSON Feed will encourage people to develop for the open web. And JSON Feed indeed is not complicated at all. For an overview of the structure, have a look at the spec. There is a JSON Feed Viewer, made by Maxime Vaillancourt, that showcases some feeds and is also great for testing your own feed, once it’s ready. Besides that, popular feed readers like Inoreader or Feedbin already added support for JSON Feed.

So I decided to give it a go and implement JSON Feed on my own site, too. Just to get an idea of what’s possible, I first looked at some sites that already provide a JSON feed, e.g. the sites of John Gruber (who also talked with the co-authors of JSON Feed on his The Talk Show podcast) and Jeremy Keith.

After that, I evaluated different ways to easily provide the feed with Craft CMS, the content management system I use for my website. For one, you could simply output a frontend template under a route, for example “/articles/feed.json”. But I decided to use a more flexible solution: The Element API plugin. Element API is a powerful plugin vor Craft that makes it really easy to create a JSON API for your entries. You simply define an array of API endpoints in a single PHP file within your craft/config folder and the plugin will do the rest automatically for you. There is also a basic example of how you can set up a JSON Feed with Element API, which is a good starting point.

With Element API, setting up a JSON Feed for my articles section turned out to be really easy. The only part that needed more care was to find the best way to pull out matrix blocks. I now simply loop through the blocks and add the individual data to the response string. If you also need to parse markdown, the parseMarkdown() function of the StringHelper class is really useful.

So you can now subscribe to my JSON feed for the articles section or have a look at it in the JSON Feed Viewer. If you have any feedback or encounter any problems, please let me know. Within the next days, I will also add feeds for the notes and links sections.

Progressive Search

Today, I added a basic weighted search to this site. You can find it here and in the footer below. Providing a search functionality is one of the pillars of an IndieWeb site, mainly because it offers improved access to the content you create and own on your site. But: Search on personal and corporate sites is a somewhat difficult topic. On the one hand, offering search more or less is imperative, but on the other hand, it is hard to get right. Most users are used to the comfort of those insanely accurate search results of Google's sophisticated artificial intelligence algorithms. Of course, this is something a normal website hardly can compete with. Nevertheless, you have to find ways to provide a sufficient search experience to your users.

For now, my site uses the standard search of Craft CMS, improved by a weighted search plugin. This is a solid start but I want to find ways to gradually improve the search experience for visitors of my site. If you look at what makes a good website search, things to consider include:

This list is by no means complete and probably I won't be able to implement all of those points. My goal is a convenient search that optimally supports the content of a personal site, offers accurate results presented in a useful and usable form, and is as fault tolerant as possible regarding user input. Or, as John Postel said:

“Be conservative in what you send. Be liberal in what you accept”

So I will take this core functionality and, focussing on the most effective design decisions, enhance it. Bit by bit. Progressively.

Data loss (also) by JavaScript

Tantek Çelik wrote a post in 2015 called “js;dr = JavaScript required; Didn’t Read.”. It was about a fundamental problem regarding sites that depend on JavaScript for rendering content: Indexability. Although search engines got much much better at indexing JS, it still remains a major problem, which I learned the hard way a few weeks ago.

On October 30, Readability closed down its “read it later” bookmarking service. Although I had not been a regular user of the service, I had created a fair amount of lists of interesting links for the students of my Interface Prototyping seminar using a site called readlists.com, a service by Readability that depended on the Readability API – and JavaScript (require.js, to be exact).

Unfortunately, Readability went offline pretty quickly, giving all users only 30 days to export their personal data. Somehow, I must have missed the Medium article or an email that announced the shutdown. So I learned about it the hard way when I opened the site with my students. No lists. No links. Gone.

Not too big a problem, I thought. And a good opportunity to show the students the beauty of the Internet Archive! But when I went there to look at the snapshot of the site, I stared at this:

Readlists Death By Javascript

The Wayback Machine snapshot of Readlists only shows a spinning wheel.

I don't want to blame the people at Readability for shutting down their service. It is also totally their decision when and how fast to go offline. But one fact remains: Once again, many users irreversibly lost their data. And this was not only due to the fact that the site was shut down, but mainly because the content was dependent on JavaScript (and an API) in a way that made it invisible to the crawler of the Internet Archive – and by that dead to history.

After five years, all that remains of Readability is a spinning wheel in the Internet Archive and a Wikipedia article.

Or, as Tantek puts it:
“If it’s not curlable, it’s not on the web.”

Books I Will Definitely Maybe Read in 2017

It’s that time of year when most people publish their „books I have read“ articles. Tim for example, and also Jeremy. I for myself am what you could call a book taster. There are a lot of books on my shelves that I started reading but somehow never finished. But this year this is going to change. Maybe.

So here’s my list of books I want to finish in 2017. By pure chance, a lot of them have the word “design” in their title. ;)

and:

We’ll see…

Starting to Write Notes

In May 2016, I flipped the switch for the redesign of this site. My last site was never updated once it was online, so I wanted to do things differently this time. Inspired by numerous people who use their web presence to share and promote their thoughts and ideas, I decided to start writing on my own site. To explore things, to share with others what I learned, to retain my thoughts and make my site a place of documentation.

Knowing that it might be hard to keep up with writing, I set myself the goal of publishing four articles by the end of the year. Somehow I indeed managed to find the time to write four articles and I found that I want to keep writing. It really is a great pleasure.

But I also noticed that my articles turned out to be a bit lengthy. Although I don’t think that this is necessarily a bad thing, sometimes a different, a shorter form of writing is necessary. For example, when you just want to write down a quick thought or when you read about something and want to share more than a link but not a lengthy article either.

So today I’m starting to take notes. Quick, raw, unpolished, short, sometimes also a bit longer. Sometimes only an image, a hasty sketch, or a drawing. But always without the need to finalize anything.