Christian Heilmann

Author Archive

Fixing a webkit-only effect using Sublime Text

Wednesday, January 22nd, 2014

Afra Noubarzadeh just blew me away with his painting using Style Sheets, completely created in Chrome Devtools. It looks like this (scaled to size):

csspainting

Afra also recorded a video of him creating it:

Then, of course, he also made me a sad, as the painting uses –webkit– only CSS prefixes.

So I decided to wield my own, if less impressive, magic and fix it for all modern and future browsers by not relying on –webkit– prefixes.

You can see the fixing process here

As Sublime Text is full of awesome, all I had to do was:

  • Fix the unclosed DIV elements (discovered as Firefox highlights HTML syntax errors in red) – search for /div\n – find all, replace \n with > and linebreak
  • Select all –webkit–[^;]+ instances
  • Copy them, and paste them after the ;
  • replace all –webkit–; with ;+Space

Voilà, it works for Chrome, Safari and Firefox. Of course, I was lucky. As Afra’s original code was amazingly clean, I could write very simple RegEx :)

Remember: do not rely on –webkit– – it will hurt you very, very soon!

Two simple syndication tricks to get wrong: have an image and don’t trust iframes

Tuesday, January 21st, 2014

Blogging is simple, but many people forget that there are freaks like me out there who have done this for quite a while who use RSS readers and that there are new folks out there who will share your links on Facebook, Google+ and other social networks.

Beastie Boys - Ill communication

Therefore it is pretty important to do two things in your posts:

  • Do not rely on iframes working
  • Do have an image for social media sites to show as a thumbnail

As to iframes, my good friend Jens Grochtdreis this morning posted about needing a new workflow in web development, proving his point by embedding two of his talks on speakerdeck (which are iframes). To me, his post looked like this in feedly:

Blog post with embeds not showing up - all I got is two headings promising content

Two headings, no content. I reported the problem on Twitter and now he linked the headings to the URLs on speaker deck. Everybody wins.

Most readers will filter out iframe content if it mixes http and https for security reasons. Something we’ll encounter more and more in the future when content security policy becomes a bigger topic (yes, the web is insecure, yes, it is our job to fix that).

The second tip about having an image is a nice-to-have but important. Having an image in your post – a real image element, not a background image – means that Facebook, Google+ and others will show this image next to your blog post title when someone shares the link on these systems. If you don’t pick a thumbnail, Facebook picks the first one. This means your link could show up next to an ad for another product and confuse potential readers. A great example I encountered the other day was Scott Hanselman’s Are you a Phony? post which, with a title like that, showed up next to an ad with an endorsement of his for his hosting service. Confusing message, much?

scott hanselman post shared on Facebook with a wrong thumbnail

Seems to me people click much more on links with contextually relevant images next to them. Thus, providing one makes it nicer for everyone.

Simple, but effective.

Myth busting mythbusted

Monday, January 13th, 2014

Today CSS tricks features an article on JavaScript animations vs. CSS animations entitled Myth Busting: CSS Animations vs. JavaScript guest-written by Jack Doyle, one of the people behind the Greensock animation platform. Not surprisingly, Jack debunks the blanket statement that CSS animations are always better for performance and functionality than JavaScript animations.

Mythbusters by Sephie monster
Mythbusters parody by Sephie-monster

Jack is doing a great job arguing his point that CSS animations are not always better than JavaScript animations. The issue is that all this does is debunking a blanket statement that was flawed from the very beginning and distilled down to a sound bite. An argument like “CSS animations are better than JavaScript animations for performance” is not a technical argument. It is damage control. You need to know a lot to make a JavaScript animation perform well, and you can do a lot of damage. If you use a CSS animation the only source of error is the browser. Thus, you prevent a lot of people writing even more badly optimised code for the web.

A blueprint for “considered harmful” articles

These kind of articles are lots of research but easy to write: you take a “common practice truth” and you debunk it by collecting counter arguments. Extra points go to having lots of performance benchmarks or demos that can not be done with the technology you debunk.

Personally, I have no problem when libraries, frameworks or software solutions are getting debunked but I have a real problem when solutions built into browsers and defined in standards are being painted as inadequate for the sake of a yet another library or – in a lot of cases of articles of this kind – your own product.

This is not helping us having a professional platform. If there are issues with performance or functionality of a standard, we should get them fixed on browser and spec level. Yes, this takes longer and we can not be the hero to the rescue that built the quick library that fixes all these problems. But we also fix it for everyone and not just for the moment as inevitably following one of these articles will be another one a few months later showing that the solution of the first one has issues.

And thus, the cycle restarts. We discuss things, we create performance tests, we find proof in a certain environment and we give once again the message that everything on the web is broken and needs people to fix it with JavaScript.

An endless source of dispute

Here are a few truths about web development:

  • It will never be perfect – the idea of the web is to release code into the unknown. All you can do is make sure you don’t deliberately make it harder for people by expecting a certain technology or hardware to be available.
  • You can always find a problem that is not possible with standard techniques – you can then use JavaScript and the DOM to solve that problem. Then you have the problem of people using your JavaScript solution and be ready to fix it for all the new platforms, browsers, environments and connection speeds to come. That’s what web development is about. That’s what browsers need to do.
  • “Technique $X is the best to use” is a fleeting statement – table layouts were the only way to create a multi column layout and got replaced by CSS. CSS layout with positioning and floats is a make-do solution, too. Flexbox is the up and coming solution to the problem of layout on the web. It is not ready across all browsers and not backwards compatible if you want all browsers to create the same layout. See where this is going?
  • There is no “one” solution for any web development problem – this is the beauty of the web. It is the “bring your own solution” platform. If you want to make it better for everybody, use standards and let the browsers worry about the performance issues and do report them to the browser makers. Everything else is patchwork and will be debunked as “not working as expected” over time
  • In 90% of the cases mythbusting articles solve one problem – the argument is not that a technology is flawed, the argument is that it is not good enough to solve problem $x. Which is OK, there will always be things that can not be done. The real question is “do you need to solve problem $x and what dependencies, issues and problems does the solution bring along with it”?
  • Everything on the web is best achieved with a mixture of technologiesCSS animations are great for certain jobs, but will not be good enough for others. You can achieve almost everything with JavaScript but that doesn’t mean you have to or should. Flash was used for a lot of things, some it was damn good for, others awful. There is no way – ever – that one technology can 100% replace another. Our use cases change and we should strive to use the technologies that gives us the best result for the least effort whilst allowing browsers to optimise for us. It is not about what we can do, it is about what makes sense to do.

All of this would not be an issue if people looked at the source of the article, the date of it and see it as a problem solution in a certain environment and time frame. What we do though is keep quoting them out of context and as gospel. Until someone else will take that argument without context and writes a mythbusting article about it.

Automating typing in screencasts with AppleScript or how to look like a hollywood hacker

Thursday, January 9th, 2014

Update: The awesome that is Stuart Langridge also created a way to do what we describe here with a plugin for Sublime Text 2. Read his blogpost to learn how

We’re busy creating a lot of screencasts for the Firefox Developer tools at the moment and it isn’t as easy as the final products make it out to be. One of the biggest issues is typing along as you speak. First of all, this is hard to do. Secondly, people keep forgetting to use an external microphone on a headset which makes the screencast sound like a bad drum and base session.

swordfish

Fret not, for my esteemed colleague William Bamberg came up with an ingenious way to work around the problem. All of this is on a Mac, so if you don’t have one, please add the info how other systems can do the same on the Wiki.

The trick is to use AppleScript to automate the typing of a certain piece of text in an editor.

You write a script using the AppleScript Editor and save it, then you use a tool like FastScripts to assign it to a keystroke and voilà, you look like a hacker in a hollywood movie.

This is the script I am using to type the content of the file /your/script.js in Brackets (I tried my normal weapon of choice – Sublime Text 2 – but it does too many clever auto indenting and closing of braces things that do mess up the output).

set fc to read POSIX file "/your/script.js" as «class utf8»
 
set the text item delimiters to (ASCII character 10)
set mylines to text items in fc
repeat with currentline in mylines
  write_string(currentline)
end repeat
 
on write_string(the_string)
  tell application "System Events"
    tell application "Brackets Sprint 15" to activate
    repeat with the_character in the_string
      keystroke the_character
      delay 0.05
    end repeat
    key code 36
    key code 123 using command down
  end tell
end write_string

You can see the result in this screencast.

This, as anything, can of course be improved and I learned along the way that AppleScript is just not for me. For someone who writes code in other languages it seems just odd – it is the uncanny valley between programming and natural language.

In any case, it should be helpful. And if everything breaks, make sure to do some extreme pair programming – that works in the movies.

This developer wanted to create a language selector and asked for help on Twitter. You won’t believe what happened next!

Wednesday, January 8th, 2014

Hey, it works for Upworthy, right?

Yesterday in a weak moment Dhananjay Garg asked me on Twitter to help him with a coding issue and I had some time to do that. Here’s a quick write-up of what I created and why.

Dhananjay had posted his problem on StackOverflow and promptly got an answer that wasn’t really solving or explaining the issue, but at least linked to W3Schools to make matters worse (no, I am not bitter about the success of either resource).

The problem was solved, yes (assignment instead of comparison – = instead of === ) but the code was still far from efficient or easily maintainable which was something he asked about.

The thing Dhananjay wanted to achieve was to have a language selector for a web site that would redirect to documents in different languages and store the currently selected one in localStorage to redirect automatically on subsequent visits. The example posted has lots and lots of repetition in it:

function english()
{
if(typeof(Storage)!=="undefined")
  {
  localStorage.clear();
  localStorage.language="English";
 window.location.reload();
  }
}
 
function french()
{
if(typeof(Storage)!=="undefined")
  {
  localStorage.clear();
  localStorage.language="French";
  window.location.href = "french.html";
  }
}
window.onload = function() {
if (localStorage.language === "Language")
  {
   window.location.href = "language.html";
  }
else if (localStorage.language === "English")
  {
   window.location.href = "eng.html";
  }
else if (localStorage.language === "French")
  {
  window.location.href = "french.html";
  }
else if (localStorage.language === "Spanish")
  {
  window.location.href = "spanish.html";
  }

This would be done for 12 languages, meaning you’ll have 12 functions all doing the same with different values assigned to the same property. That’s the first issue here, we have parameters on functions to avoid this. Instead of having a function for each language, you write a generic one:

function setLanguage(language, url) {
	localStorage.clear();
 	localStorage.language = language;
 	window.location.href = url;
 }
}

Then you could call for example setLanguage(‘French’, ‘french.html’) to set the language to French and do a redirect. However, it seems dangerous to clear the whole of localStorage every time when you simply redefine one of its properties.

The onload handler reading from localStorage and redirecting accordingly is again riddled with repetition. The main issue I see here is that both the language values and the URLs to redirect to are hard-coded and a repetition of what has been defined in the functions setting the respective languages. This would make it easy to make a mistake as you repeat values.

A proposed solution

Assuming we really want to do this in JavaScript (I’d probably do a .htaccess re-write on a GET parameter and use a cookie) here’s the solution I came up with.

First of all, text links to set a language seem odd as a choice and do take up a lot of space. This is why I decided to go with a select box instead. As our functionality is dependent on JavaScript to work, I do not create any static HTML at all but just use a placeholder form in the document to add our language selector to:

<form id="languageselect"></form>

Instead of repeating the same information in the part of setting the language and reading out which one has been set onload, I store the information in one singular object:

var locales = {
    'us': {label: 'English',location:'english.html'},
    'de': {label: 'German',location: 'german.html'},
    'fr': {label: 'Français',location: 'french.html'},
    'nl': {label: 'Nederlands',location: 'dutch.html'}       
};

I also create locale strings instead of using the name of the language as the condition. This makes it much easier to later on change the label of the language.

This is generally always a good plan. If you find yourself doing lots of “if – else if” in your code use an object instead. That way to get to the information all you need to do is test if the property exists in your object. In this case:

if (locales['de']) { // or locales.de - the bracket allows for spaces
	console.log(locales.de.label) // -> "German"
}

The rest is then all about using that data to populate the select box options and to create an accessible form. I explained in the comments what is going on:

// let's not leave globals
(function(){
  // when the browser knows about local storage…
  if ('localStorage' in window) {
    // Define a single object to hold all the locale 
    // information - notice that it is a good idea 
    // to go for a language code as the key instead of
    // the text that is displayed to allow for spaces
    // and all kind of special characters
    var locales = {
        'us': {label: 'English',location:'english.html'},
        'de': {label: 'German',location: 'german.html'},
        'fr': {label: 'Français',location: 'french.html'},
        'nl': {label: 'Nederlands',location: 'dutch.html'}       
    };
    // get the current locale. If nothing is stored in 
    // localStorage, preset it to 'en'
    var currentlocale = window.localStorage.locale || 'en';
    // Grab the form element
    var selectorContainer = document.querySelector('#languageselect');
    // Add a label for the select box - this is important 
    // for accessibility
    selectorContainer.innerHTML = '<label for="languageselectdd">'+
                                  'Select Language</label>';
    // Create a select box 
    var selector = document.createElement('select');
    selector.name = 'language';
    selector.id = 'languageselectdd';
    var html = '';
    // Loop over all the locales and put the right data into 
    // the options. If the locale matches the current one,
    // add a selected attribute to the option
    for (var i in locales) {
      var selected = (i === currentlocale) ? 'selected' : '';
        html += '<option value="'+i+'" '+selected+'>'+
                 locales[i].label+'</option>';
    }
    // Set the options of the select box and add it to the
    // form
    selector.innerHTML = html;
    selectorContainer.appendChild(selector);
    // Finish the form HTML with a submit button
    selectorContainer.innerHTML += '<input type="submit" value="go">';
    // When the form gets submitted…
    selectorContainer.addEventListener('submit', function(ev) {
      // grab the currently selected option's value
      var currentlocale = this.querySelector('select').value;
      // Store it in local storage as 'locale'
      window.localStorage.locale = currentlocale;
      // …and redirect to the document defined in the locale object
      alert('Redirect to: '+locales[currentlocale].location);
      //window.location = locales[currentlocale].location;
      // don't send the form
      ev.preventDefault();
    }, false);
  }
})();

Surely there are different ways to achieve the same, but the important part here is that an object is a great way to store information like this and simplify the whole process. If you want to add a language now, all you need to do is to modify the locales object. Everything is maintained in one place.