Blog

CSS Trick: Expanded Hit Areas

When developing for touch devices, sometimes you need a button’s clickable area to be larger than its size (for usability’s sake). With CSS psuedo elements, there’s a way to do that without cluttering your markup or breaking your layout. Here’s the idea: place an invisible element on top of your button that’s the size of the hit area you’re looking for.

.button::before {
position: absolute;
display: block;
content: ' ';
top: -10px;
right: -10px;
bottom: -10px;
left: -10px;
}

The element you’re applying this to must have its positioning explicitly set (relative, absolute, fixed) otherwise the the overlay won’t be positioned correctly—it’ll be positioned relative to the ancestor that has its positioning set.

.button {
position: relative;
}

Demo

Here it is! The red box is the pseudo element that expands the hit area:

Sketch: Particle Beats

After trekking to Petsmart this evening to get a Furminator, I sat down to try my hand at visualizing music. With a mix of Processing.org + Minim + some minor post in AE, this is a snippet of the result!

What’s going on: Each particle has a random mass. As the music plays, an FFT breaks down the sound. A spike in volume in the low frequencies energizes high-mass particles, and a spike in volume on higher frequencies energizes the low mass particles. If the energy of a particle reaches a predefined threshold, it spawns children (visible at the end). There are some other forces at play as well in order to get just the right result, but this is the gist.

JSX Scripting with Creative Suite Extensions: In Practice

JSX scripting makes controlling Adobe Creative Suite from an extension you’re developing a breeze. Scripting opens up the realm of creating guides, selecting tools, creating layers, running filters, and so on. To get you started, Adobe Extension Builder creates a basic *.jsx file with a sample function in every new project:

function jsxFunction() {
// ... your code goes here ...
return '<object><property id="success"><true /></property></object>';
}

To call that function from AS3, it’s easy:

var result:SyncResult = CSXSInterface.instance.evalScript('jsxFunction');

The Workflow

First, install the Scripting Listener plugin. With it installed, whenever you do something in Photoshop/Illustrator/etc, it will write the code needed to perform those steps to ScriptingListenerJS.log on your desktop. Copy the parts you need from there and put them in your *.jsx file, wrapped in a function. Then just callevalScript() with the function name, and you’re good!

Function Arguments

Sometimes you might need to pass a value to a JSX function from AS3—maybe it’s a coordinate, maybe it’s the path of a file, maybe it’s a color. Arguments is where life gets janky. In CS4 products, only one argument is supported. And in CS5+, certain characters like quotation marks and backslashes will cause aPlugPlugRequestFailed status—for no valid reason.

The solution? Feed evalScript() arguments as if you’re feeding a bird masticated baby food. Concatenate your arguments and hex-encode them. This will prevent mysteriously-forbidden characters and bypass CS4′s limit of only one argument.

Encoding Arguments in AS3

public class JSXArguments { 
public static function encode(arguments:Array):String {
return hexEncode(arguments.join('__:__'));
}
private static function hexEncode(str:String):String {
var result:String = '';
var hex:String;
var i:int = 0;
while (i < str.length) {
hex = str.charCodeAt(i++).toString(16);
while (hex.length < 3) hex = '0' + hex;
result += hex;
}
return result;
}
}

// example usage:
CSXSInterface.instance.evalScript('doSomething', JSXArguments.encode(
[1, 2, 'Hel/lo\\ Wo/rld!']
));

For simplicity’s sake, this only supports basic integral types—ints, floats, strings. Furthermore, when you use your arguments in your JSX script (explained below), they’ll be strings. So if you want to preserve a number, you’ll have to call parseIntor parseFloat to convert it. If you need to pass objects or arrays, you’ll need to get fancy and serialize them before hex-encoding—JSON.encode works wonders.

Decoding Arguments in the JSX Script

function decodeArgs(argStr) {
if (argStr) {
var decodedArgs = '';
for (var i = 0; i < argStr.length; i += 3) {
decodedArgs += String.fromCharCode('0x' + argStr.substring(i, i + 3));
}
return decodedArgs.split('__:__');
}
return [];
}

// example usage:
function doSomething(encodedArgs) {
var args = decodeArgs(encodedArgs);
var x = parseInt(args[0]); // 1
var y = parseInt(args[1]); // 2
var message = args[2]; // "Hel/lo\\ Wo/rld!"
// ...
}

Wrap-up

Scripting opens up tons to your extension—there are just a few bizarre quirks to work around. Hopefully this guide helps! If anything written here is fuzzy or could be elaborated on, please ping me on Twitter.

Actually-native Alerts in AIR

A few libraries (as3nativealertlib and AirAlert) claim to provide native alert dialogs to Flex/AIR—but each one emulates the UI, which isn’t quite ideal.

A workaround is to use the HTMLLoader class to get totally-native modal alerts laid out by the OS. This works by leveraging Flex/AIR’s integration of Webkit into the runtime. Calling the alert method of the window triggers an alert just as a web browser would.

var htmlInterface:HTMLLoader;
function alert(message:String):void {
if (!htmlInterface) {
htmlInterface = new HTMLLoader();
htmlInterface.loadString('<html><head></head><body></body></html>');
}
try { htmlInterface.window.alert(message); }
catch (e:Error) {}
}

Not exactly the cleanest of solutions… but it works! The only downside is the inability to set the title of the dialog.