Friday, November 28, 2014

css spritesheets

CSS spritesheets, putting a bunch of images in one big image (so that http round trips are minimized) and then using CSS to just show the correct image subset of the full sheet, is a good trick to know about. (I suddenly started wondering if advances in the http protocol would make them less crucial, and allow multiple files to be downloaded in one gulp, so to speak.. googling to check that out brought me to a page saying you should embed images as encoded text in the CSS which seems to be taking it a bit too far!)

Anyway, I found it convenient to use good ol' ImageMagick. This page goes into some detail, but the net-net was doing:
convert img1.png img2.png img3.png -append spritesheet.png
was all I needed. That gave me a single .png with all the images in a vertical stack. I then made a quick perl script to generate the css, something like
.img {
    width:50px;
    height:50px;
    background-image: url('spritesheet.png');
}
.img.thing1{
       background-position: 0px 0px
}
.img.thing2{
       background-position: 0px -50px
}

(I had 25 of these to do). The important thing here is the offset, which is increasingly negative for each subsequent image.

The HTML was then something like
<div class="img thing1"></div>
<div class="img thing2"></div>
This raises best practices / style questions. W3Schools recommends using the img tag with a placeholder for the src (lest your html be invalid), ala:
<img class="thing1" src="img_trans.gif">
I see that it's kind of cool to keep things an image (even better would be list item tags or other semantically meaningful html tags) but going back to the old "transparent GIF" placeholder thing gives me the creeps!

Also you can run your generated file through an online image compressor... and there are even other online tools to smush the image together and give you the resulting CSS.

Thursday, November 27, 2014

localStorage

One of those things I grew up living with out (because it didn't exist in most browsers) and so don't always think of: localStorage is trivial to use in modern browsers, and provides decent support when you want to store some state across sessions, but don't want to make up a backend server to support it.

You have to be ok with not getting state back if the user is using a different device or browser, but then again, that's always true unless you've actually made some kind of server-side account system. (Which also has UX implications, in terms of a lot of people have "make an account to use this fatigue". And also "link to my FB account" fatigue.)

Anyway, window.localStorage; it's just sitting there, waiting for you, with old Old Skool messing with cookies.
localStorage.setItem("someKey",someThing);
and later
localStorage.getItem("someKey");
or you can even use array-like syntax:
localStorage["someKey"];

The only caveat it is many or all browsers will coerce your data to a string, so most likely you want something like
localStorage.setItem("someKey", JSON.stringify(someThing));
and
someThing = JSON.parse(localStorage.getItem("someKey"));
(with an appropriate safety checks)

Sunday, November 16, 2014

yosemite fullscreen

Even though it was reviled as being inconsistent and unpredictable, I preferred the old OSX "zoom" button behavior, where it (kinda sorta) maximized the window within the context of the current set of windows over the new "take over the whole screen world" pattern it has in Yosemite. I often want a bit more real estate for a given window, and rarely am I thinking "boy I wish I was looking at this window AND NOTHING ELSE MATTERS IN MY COMPUTER'S WORLD".

Besides predictability (especially when resizing browsers; some people found it odd that it didn't always try to be as wide as possible) I suppose Apple is trying to catch an iOS-like sense of "focus on this one thing" monotasking, and so they hide the dock and title bar. Personally, I think this is a UX misthink; a flavor of multitasking (or at least quick task switching) is fundamental to many people's use of a laptop or desktop.

(I like how Windows 7 did it; the window still takes up the full screen, but then you can reposition it)

Anyway, you can hold "option" when you click the green circle, and then gets the old zoom behavior; I just wish there was a way to switch which one was the default.

Friday, November 14, 2014

friday 5:30 pm kinds of problems and shaking old habits

One problem with being in the industry a decade and a half or so is that old habits die hard.

FOR EXAMPLE, I suspect some possible future employers will be thinking I'm a cave-dwelling Netscape 4.7 barbarian unless I go refactor out the use <table> for layout purposes on those sites I wrote in 2005 or so.

(THAT SAID, CSS only recently is anywhere near caught up with tables in its ability to position multiple objects relative to each other- the fact that this page on fluid width equal height columns even suggests monstrosities such as
margin-bottom: -99999px; 
padding-bottom: 99999px;
points to some serious limitations! (That hopefully flexbox et al will be resolving...) But really, I think <table> is a shibboleth, since if you're using <div> for display, you're pretty far from the html5 dream of the Semantic web anyway..)

ANYWAY. Old habits. One was in my use of console.log(). Earlier versions of it weren't very smart, it would just cast everything to a string.  And so I developed habits of doing stuff like this:
console.log("the thing is "+JSON.stringify(thing));
but that of course meant I would miss out on chrome's ability to display the object in the console in clever, expandable way.
But console.log happily also takes multiple arguments now too! So you can do
console.log("the thing is ", thing);
which is the best of all worlds; getting rid of JSON.stringify() cruft, having an expandable view of thing, and still having a human readable caption.

FINALLY, before I realized/remembered about how flexible chrome's console.log() is, I learned the hard way that JSON.stringify() on a variable set to a function gets very weirdish results. Just don't do it. I thought I was going nuts with my ability to curry a function until I realized it was because I was throwing JSON.stringify() into the mix.

Thursday, November 13, 2014

getting closure

Just a reminder about Self Excuting Anonymous Functions.. they're a great way to avoid polluting a page's global name space if you are making a script to be included on someone else's page (like in the window.onload event, where you don't want to leave a remnant.)

Some code I did today had bits like this:

(function (){
var oldOnLoad = window.onload;
window.onload = function(e){
//DO SOME COOL STUFF
if(typeof oldOnLoad  == "function"){
oldOnLoad(e);
}
}
})();

That was a decent way to not overwrite any existing window.onload code, but oldOnLoad isn't in the global space, because of the use of the closure.

best practices in templating

Some dueling articles! You Have Ruined HTML is negative about the "hipster languages" and the mix of HTML destined for the DOM with various controlling structures. The rebuttal is HTML Wasn't Made For Apps.

Among other things, the former article talks about the complexity of the looping filters (sometimes the complexities they introduce in the code to get some sweet, sweet syntactic sugar is a poor tradeoff) and the opacity of the error handling and debugging.

The rebuttal points out, among other thing, how ugly building DOM ala React is. This reminded me of the bad old days of Perl CGI; there were libraries to build a page in code, via structural elements, but it was a much better idea to use Perl's << quote syntax for extended, multiline quotes, embedding HTML as minitemplates, complete with variable substitution. (Sometimes I still feel there's a divide with coders who are closer to backend engineers, and want to avoid making raw DOM, and coders who are closer to designers, who want to make DOM directly, but with the flexibility of looping and conditional structure.)

The answer, as usual, is somewhere in the middle. For a while I had a bias for treating the DOM as a static billboard the Javascript would write to (at carefully predetermined and loosely coupled points) but I've learned how handy a good templating tool can be.  I think the best practice is to try to keep your chunks of template as modular as possible, and moving complex logic to code. (Where it's probably easier to test against anyway)

I'm kind of interested in what choice the various frameworks make in terms of tag-like, attribute-based markup (e.g. <div ng-if="somecondition"></div>) vs "out of band" markup (for instance with {{handlebar}} style structure.)  Sometimes the former seems a little cluttered to me, because it mixes the semantic levels; your control structures look like DOM content you'd expect the browser to render, and when you inspect elements you see that unrenderable stuff. On the other hand, the {{handlebar}} tags will make a terrible mess if you ever look at code in unprocessed form, and so are a bit less designer-friendly.

Sunday, November 9, 2014

remove smart quotes via javascript

I always have minor twinges that I am not typographically-morally upright enough to prefer "proper quotes" to "inch marks". 

But smart quote characters create more problems than they are worth. I used to run suspect text through the  Dan Hersam's Filter but I realized I should just take the basic code and put it more directly into my workflow. 

Here's the function I came up with, pass in the id of an input element and it will replace its contents with a safer, if less typographically pure, version.


function unsmartquote(id){
    var element = document.getElementById(id);
    var s = element.value;

    s = s.replace(/[\\u2018\\u2019]/g, "'");
    s = s.replace(/[\\u201C\\u201D]/g, '"');
    s = s.replace( /\\u2014/g, '--' );
    s = s.replace( /\\u2026/g, '...' );
    s = s.replace( /\\u00A9/g, '&copy;' );
    s = s.replace( /\\u00AE/g, '&reg;' );
    s = s.replace( /\\u2122/g, '<sup>TM</sup>' );
    s = s.replace( /\\u00BC/g, '<sup>1/4</sup>' );
    s = s.replace( /\\u00BD/g, '<sup>1/2</sup>' );
    s = s.replace( /\\u00BE/g, '<sup>3/4</sup>' );
    s = s.replace(/[\\u02DC|\\u00A0]/g, " ");
    element.value = s;

}

It took a little longer than I had expected to make this, I got bit by double slash for the unicode escape sequence merging into single slash by the time I was trying to copy and paste the code

Friday, November 7, 2014

zuck's half-answer to "why a second app"



(This is probably just a "things that irks me rant" in a "let's talk about some UX!" shell)

The Verge has an article: Mark Zuckerberg finally explains why he forced you to download the standalone Messenger app.

The need to install Messenger as a separate app (after months and months of ignoring the main FB app's pleas to, with promise of how "fast" it was) irked me mightily. I consider smartphone front page app space valuable - but I am interested enough in getting notified about activity on FB (whether post comments or messenger, the difference isn't all that much to me, really) that I had to carve out two places, since I would miss the notification badge on a secondary page. (Later I came to split the difference: the only app folder I have on my iPhone's first page is now "social media" in general, including Messenger, some dating sites, and some things for work I usually use on the laptop, while FB's main app gets to sit on the page itself.)

Anyway, for me the heart of his explanation was:
We saw that the top messaging apps people were using were their own app. These apps that are fast and just focused on messaging. You're probably messaging people 15 times per day.
 I am messaging people 15 times a day. Or at least 4 or 5. But it's the "But not on FB" that's Zuck's problem, the sentence he leaves out at the end of that. He'd love FB to be as critical for people in the quick messaging sense as it is in FB's traditional niche.

I don't know what FB's IM numbers are, but if the usage by me and my friends is anything to go on, the IM there is secondary. You use it when you aren't looking for a quick response, and you use it because if someone is on FB, they have access to a keyboard, and it's probably more physically convenient to tap out a response. (I know I'm talking like an old guy, where the web is more my native communication form than mobile.)

But FB is the big dog that sees this bone some other dogs are fighting over (Apple's iMessage and WhatsApp in particular) that, despite the delicious bone it has on its own plate, it wants to go and get a piece of that, no matter how many user's toes they step on. They want to own quick communication as well as the longer term "oh yeah that jerk I knew in middle school" longer term stuff.

Anyway.

FB, Tumbler, and Twitter collectively sucked a lot of the air from the independent web of the mid 2000s, because their value proposition of "build a centralized collection of possibly interesting stuff from people you know and/or expect to make or find cool stuff" is strong; it beats having to go from site to site, and hardly anyone bothered with RSS feeds for that (which I tend not to like, because it takes away the UX flavor I find critical in knowing where I saw something...)

the principles of rich web applications

7 Principles of Rich Web Applications is a pretty good read!
  1. Server rendered pages are not optional
  2. Act immediately on user input
  3. React to data changes
  4. Control the data exchange with the server
  5. Don’t break history, enhance it
  6. Push code updates
  7. Predict behavior