Tiffany B. Brown A web log about web development and internet culture with frequent detours into other stuff. Mon, 04 Aug 2014 21:12:41 +0000 en-US hourly 1 On freelancing Mon, 04 Aug 2014 21:12:41 +0000 I don’t trust easily and assume the worst. I rarely ever feel secure, safe, or happy. Asking for help embarrasses and intimidates me. Self-promotion makes me feel gross. I’m not sure people will like me. And I almost never believe things will ever work out.

Somehow, despite all of this, I ended up freelancing.

Freelance work tests every one of my fears and hang-ups. Every. Single One. I have to trust that people will pay me, and pay me on time. I have to trust that I am not setting expectations that I can’t meet. I have to ask people to help me earn a living by asking for work and promoting my skill-set.

Most of all — and this is the hardest of all — I have to trust that things will all work out.

Self-confidence does not come easy to me. Every pulled project, every stall, every rejection, feels like a personal insult or a commentary on my worth as a developer. I have to remind myself that budgets dry up, clients hire full-time staff, and someone is always promising to do it faster and cheaper. It’s not easy, though, especially when you are faced with a dry month of no work and a dwindling bank balance.

I am still learning how to do this. I’m experimenting with what to charge and how best to price a project. I’m figuring out how and where to market myself. I’m tinkering with my service and product offerings. I’m running a business, while also trying to find the time to boost my technical skills should I ever have to become an employee once more.

Now despite the somber tone, this post is actually meant to celebrate a milestone: my freelance web development business turned one in July. This journey continues to test me and push me beyond my comfort zone. Even with this persistent sense of fear and personal failure nestled in my belly, I am happier than I’ve been in quite some time.

]]> 0
OS X, Python: clang: error: unknown argument: ‘-mno-fused-madd’ Thu, 01 May 2014 13:00:59 +0000 While attempting to install Fabric for a project, I ran into the following error message (straight from my pip.log).

clang: error: unknown argument: '-mno-fused-madd' [-Wunused-command-line-argument-hard-error-in-future]

clang: note: this will be a hard error (cannot be downgraded to a warning) in the future

error: command 'cc' failed with exit status 1

Some Googling revealed that this is an issue with the XCode 5.1 update. This update treats unrecognized command-line options as errors. And has been causing a lot of facepalming for users of Ruby gems and Python libraries. The fix is a simple one. Just open up Terminal and type:

export CFLAGS=-Qunused-arguments
export CPPFLAGS=-Qunused-arguments

Then run pip install [package name] as usual. If you need to use sudo to install packages with pip, use sudo -E instead:

sudo -E pip install fabric


]]> 0
HTML5: Determining which validation constraint triggered an error Sun, 23 Mar 2014 18:11:44 +0000 When working with custom error messages and HTML5 forms, it helps to know which validation constraint rule was broken so that we can provide a tailored error message.

When a form field’s input is invalid, the browser fires an invalid event on that field. Let’s say that we have the following form with a required email field.

<form action="/handler" method="post">
        <label for="email">E-mail address:</label>
        <input type="email" id="email" name="email" required>
        <button type="submit">Submit</button>

When this form is submitted, capable browsers will check whether the value of the email field meets the constraints of the input field’s type. Since it’s also a required field, its value will pass the validation test only if:

  • the user entered a value; and
  • the value entered matches the email address pattern.

If it fails to meet either constraint, the browser will fire an invalid event that we can listen for

var email = document.querySelector("#email");

email.addEventListener('invalid', function(e){'Double-check what you entered in the e-mail field.');

A message like the one above works, but leaves some ambiguity about what’s causing the error. How do you, the developer, determine which validation constraint wasn’t met?

Here’s where the validity IDL attribute comes in.

The validity attribute returns a ValidityState object. It contains the following properties:

  • badInput
  • customError
  • patternMismatch
  • rangeOverflow
  • rangeUnderflow
  • stepMismatch
  • tooLong
  • typeMismatch
  • valueMissing

Each of these properties has a value of true or false depending on which constraint the input fails to meet. Not all of these properties apply to every input type, however. For example, input.validity.rangeOverflow, will never be true for a text field.

In addition to the ones above, the ValidityState object also contains a valid property that indicates whether the field is valid or not, but not what kind of error occurred.

In this case, a mistyped email address — such as — would make the value of email.validity.typeMatch equal to true. All other properties would be false.

A missing email address, on the other hand, would cause email.validity.valueMissing to have a value of true, while all other properties would have a value of false.

We can check the value of these properties within our invalid event handler, and display a message that explains specifically what’s wrong with the input (or lack thereof).

var email = document.querySelector("#email");

email.addEventListener('invalid', function(e){
    var msg;
        msg = 'Your email address is missing';
        msg = 'Your email address is invalid';

View a working example on CodePen.

Let’s look at another example, this time using a pattern. We’ll create a text field for U.S. postal codes (ZIP Codes).

<form action="/handler" method="post">
        <label for="zip">ZIP code</label>
        <input type="text" id="zip" name="zip" maxlength="5" size="5" minlength="5" pattern="[0-9]{5}" required>
        <button type="submit">Submit</button>

ZIP Codes are five digit numeric strings. We are using a very loose pattern here for the pattern attribute. We’re just checking that our input contains five digits ranging from 0 through 9. Matching actual ZIP Codes is a bit more complicated, but this is good enough for this example.

Our invalid event handler looks much the same, but this time, we’ll check the value of the patternMismatch property.

var zip = document.querySelector("#zip");

zip.addEventListener('invalid', function(e){
    var msg;
        msg = 'We need your ZIP code. Please include it.';
        msg = 'Your ZIP code should contain exactly five digits.';

Working example on CodePen.

Once these invalid fields meet the validation constraints, the user will be able to submit the form.

]]> 0
Why I deleted my LinkedIn Account Mon, 10 Feb 2014 13:00:09 +0000 Back in November, I pulled the plug on my LinkedIn account after several months of considering it. Why? In a word: value.

LinkedIn has lost all of its value for me.

What? How? I mean it’s the first place recruiters and HR people go to find and learn about candidates, right?

Well yes. And that’s precisely the problem.

Recruiters have very little value to me. Perhaps this is also true for most developers. Now, I don’t mean to suggest that I am the kind of brilliant developer who can work wherever she wants. But I am a developer with an excellent sense of:

  • the kind of work I’d like to do;
  • the work culture I am happiest and most successful in;
  • the cities in which my husband and I would like to live; and
  • what kind of commute I’m willing to tolerate.

Messages from Silicon Valley companies, or VC-Funded Social Media Ad Startup in Santa Monica/Irvine/Commutinghelltopia aren’t going to work for me. Offers from Atlanta (where I used to live) or Charlotte, NC (Really?) certainly won’t.

Now, LinkedIn’s boneheaded product changes didn’t help. I hated the new design. Endorsements became meaningless to me once a high school friend endorsed me for information architecture. Notifications for those endorsements, and other minor activities just added to a stream of noise. Soon the number of useful interactions I had on LinkedIn were outweighed 10:1* by interactions that were useless. So I deleted my account and haven’t looked back.

* A totally made up ratio, but one that captures the magnitude.

]]> 0
Subtitles and captions with WebVTT Sun, 15 Dec 2013 06:08:22 +0000 One drawback of HTML5 multimedia is accessibility. For hearing impaired users, audio and video content is nearly-useless without an alternative. This is where the track element and WebVTT come in handy.

Excerpt from 'Sita Sings the Blues'

What WebVTT looks like when combined with @font-face.

WebVTT, short for Web Video Text Tracks, can be used to provide timed subtitles and/or captions for multimedia content. WebVTT files are plain text, but must be served with a text/vtt header.

Even though it’s plain text, WebVTT does adhere to a special format. The first line must be WEBVTT, and separated from a series of cues by a blank line. Each cue is made of a start time, an end time, and some descriptive text — either subtitles, translated dialogue, or a description of background audio. Below is an example of dialogue from an excerpted clip of Nina Paley’s Sita Sings the Blues.


0:00:05.000 --> 0:00:11.000 
When? I don't remember what year. There's no year. 
How do you know there's a year for that?

0:00:11.000 --> 0:00:12.800 
I think they say the 14th century.

That first line marks the boundaries of our first cue. It starts at roughly 5 seconds into the clip and ends at 11 seconds. During that time, the text below will appear on screen. Cues must be separated by a blank line. Our next cue begins at 11 seconds and ends at 12.8 seconds.

Cues and CSS

In Chrome, Safari iOS7, and Opera 16+, we can style our cues using CSS and the ::cue pseudo-element.

    font:18px / 1.5 verdana, sans-serif;

Firefox and Internet Explorer don’t support this just yet. Firefox’ support for ::cue is in progress. I assume the same is true of Internet Explorer.

Simple WebVTT Markup

WebVTT supports a subset of HTML tags and a few of its own elements. We can bold or italicize text using <b> and <i> elements. It’s also possible to specify the language of a particular snippet of cue text using the <lang> element.

Perhaps most useful is the ability to mark up different speakers using voice elements or the <v> tag.

0:00:16.500 --> 0:00:20.499 
<v Man1>That's when the Moguls were ruling. Babur was in India.</v>
<v Woman>The 11th then...</v>

Then we can style them using the ::cue psuedo-element as a function.



Browser support for this is still a bit scattershot, though. Chromium and its derivatives (Chrome and Opera) have the most robust support for WebVTT features. Those browsers support most of WebVTT’s tags, and allow the most control over the appearance of captions and subtitles with CSS. Chromium-based browsers even support using @font-face with WebVTT cues.

Using with <track>

To use WebVTT with the track element, you need to set your path to the WebVTT file as the src attribute. By default, track elements are subtitles. If you like them to be treated as captions by the browser, set the kind attribute to captions. Though a label isn’t required, some browsers — notably, Internet Explorer — will display less-than-helpful defaults. Make your label a descriptive name.

<track kind="captions" srclang="en-US" src="dialogue.vtt" label="English">

The srclang attribute is only required when kind="subtitles". Without it, subtitles won’t work. The value of srclang should be a BCP 47 language code. We’ve included it here even though our track is a captions track. Safari will prioritize the srclang as a label when both are present.

Most browsers support the track element for the video element only. For audio, there are two options. Either:

  • include a text transcript in the reference document along with your audio media; or
  • serve audio files with the video tag

You can see how it all comes together in the related demo.

Want more?

I cover HTML5 audio and video, as well as the ins-and-outs of WebVTT in Jump Start HTML5 Multimedia from Learnable and SitePoint.

]]> 0
Faux placeholder clearing with CSS Mon, 09 Dec 2013 11:00:10 +0000 Maybe you’re like me, and you’re not crazy about the way the placeholder attribute works for text fields. I think the placeholder text should clear once the input has focus. Instead, the text only clears after the user starts typing.

The good news is that we can modify this behavior without (completely*) compromising accessibility by changing the color of the placeholder text to transparent (or using an RGBa/HSLa color with a 0 alpha).

Below, is a snippet of CSS that shows you how to do this. It uses vendor-specific pseudo-elements, which is currently the best/only way to do this. In the future, I suspect we’ll have a standard placeholder or input-placeholder selector. For now, we need to take this less-than-standard approach.

    color: transparent;
:focus::-moz-placeholder { 
    color: transparent;  

:focus:-ms-input-placeholder {  
    color: transparent;

Here we’re using the transparent keyword of the color property, but you could also use rgba(0,0,0,0) or background: hsla(0%,0%,0%,0);.

And a demo

*I haven’t actually tested how the placeholder attribute works with assistive technology, so keep that in mind. If you happen to, please let me know if you run into problems.

]]> 0
Date input in HTML5: Restricting dates, and a thought for working around limitations Thu, 24 Oct 2013 21:22:52 +0000 You probably know that HTML5 introduced a date input type, which constrains the value to a valid date string.

<input type=”date”> largely eliminates the need for JavaScript-based date pickers such as the one found in jQuery UI. In browsers that support the type, we can pick a date using the browser’s native widget. Below is an example of this widget in Chrome.

Native date widget in Chrome

Restricting input with min and max

We can restrict date input in a few ways. The easiest is by using the min and max attributes. Set the value to a valid date string using the YYYY-MM-DD pattern defined in RFC3339.

<input type="date" min="2013-10-01" max="2013-10-20">

In Chrome and iOS Safari, this will keep the user from selecting dates that are earlier than 1 October 2013 or later than 20 October 2013.

Date picker in Chrome with mininmum and maximum dates.

Using <datalist>

The datalist element is another way we can shape date input. Using datalist presents the user with a pre-selected list of dates, and the option to choose another, at least in Chrome, Opera, and Safari for iOS.

Date picker in Chrome with datalist.

We can even add a label attribute if, for example, we wanted to feature a list of holidays.

<input type="date" id="date" name="date" list="thesedates">
<datalist id="thesedates">
    <option label="Groundhog Day">2014-02-02</option>
    <option label="Valentine's Day">2014-02-14</option>
    <option label="Flag Day">2014-06-14</option>

Date picker with datalist and labels.

Can’t eliminate days, but here’s a suggested workaround

What we can’t do yet, however, is eliminate classes of days from our input. We can’t, for example, prevent selection of weekends or disallow Mondays purely through markup. Instead, we’ll need to do a little more work, using the HTML5 validation API, and the native JavaScript Date object.

Let’s take a look at some code that will display an error if the date selected is a Monday.

var date = document.querySelector('[type=date]');
function noMondays(e){
    var day = new Date( ).getUTCDay();
    // Days in JS range from 0-6 where 0 is Sunday and 6 is Saturday
    if( day == 1 ){'OH NOES! We hate Mondays! Please pick any day but Monday.');
    } else {'');

When our form is submitted, our user will be notified that they haven’t picked a date that we like. You should probably tell your user that X days are not permitted before they submit a date, of course. Just include some explanatory text near the field.

For weekends, you’ll need to test whether new Date( ).getUTCDay(); equals 0 or 6, but the general principle is the same.

Then we can use the :invalid psuedo-class to highlight that this form data is invalid.

Why not just stick to JavaScript-based date pickers, then?

Since the date type has this limit, you may ask why we should use it and not stick to existing widget scripts. The best answer I have is: touch and scripting overhead. JavaScript-based date pickers are usually prone to fat-finger input issues. Both iOS and Android (Google’s version, at least) have tap-optimized date input controls used by browsers on those platforms. It’s a bit more seamless for the user.

And by using a native type where possible, we eliminate the JavaScript code, CSS, and DOM operations that go with it. That’s particularly important on smartphones where network capacity is more of a concern.

]]> 0
Use IDL attributes to test <input type=""> support Wed, 23 Oct 2013 16:00:18 +0000 HTML5 input control types still have a ways to go before every type is supported in every browser. In the meantime, you may still find that you need to feature-test whether a particular type is supported. Do this by checking the value of the type IDL attribute.

IDL attributes are defined by the HTML5 specification for each element or object. This allows us to retrieve our element properties or attributes using dot syntax. Though IDL attribute values often mirror DOM attribute values, they’re not the same. In fact, sometimes — as with the type attribute of the input element — they’re quite different.

As outlined in the HTML5 specification, if a user agent doesn’t support a particular form type, the value of its IDL type property must be text. Take a look at the form below.

<form action="/script" method="post">
    <input type="date" name="eventdate" id="eventdate">
    <button type="submit">Save</button>

In browsers that don’t support the date input type, the value of document.getElementById('eventdate').type will be text. But if you use document.getElementById('eventdate').getAttribute('type'), the value returned will match the value of type as authored, that is: date.

You’ll run into this with jQuery and its .attr() as well. To use our example from above, $('#eventdate').attr('type') will return the DOM attribute value rather than the IDL attribute value. To retrieve the IDL value, you should retrieve the element instead of the jQuery object, and then check its IDL value. We’d just need to rewrite $('#eventdate').attr('type') to be $('#eventdate')[0].type.

]]> 0
Oh hey, I wrote a book. NBD. Wed, 16 Oct 2013 01:11:39 +0000 I wrote a book called Jumpstart HTML5 Basics, published by SitePoint. It is what it sounds like: all about HTML5, but for a beginner (okay, maybe an intermediate developer) audience. I only have three things to say about it.

  1. Writing a book is hard, especially when you are juggling full-time work
  2. I tried to aim it at beginners, but I think I overshot the target. I hope you find it useful anyway.
  3. Please buy it.


]]> 0
Range controls and padding in IE10+ Tue, 15 Oct 2013 23:38:43 +0000 While working on a video player for a forthcoming book, I noticed a peculiar spacing issue with <input type=”range”> that affected the layout of this player.

Internet Explorer does something a little weird that no other browser does: it throws several pixels of padding along the top and bottom of the range element by default (Figure 1).

Padding around  in Internet Explorer 10.Padding around <input type="range"> in Internet Explorer 10.

There’s so much padding that you don’t actually need to touch the range element in order to change its value — just bring your mouse or finger within a 20 pixel (or so) vicinity. The fix is easy, of course. Just use CSS to change padding ex: padding: 0;.

]]> 0
Living the dream Wed, 11 Sep 2013 12:00:20 +0000 Since being laid off from Opera in January, I haven’t been very vocal about what I’m up to. That was a deliberate choice on my part, since I hadn’t really figured it out. Losing a job, particularly a high-profile job with a lot of visibility and expectations is always tough. And it was compounded by the timing.

For a few months, I enjoyed funemployment. I searched for jobs, but not too hard. I interviewed here and there. I even picked up a few part time hours doing maintenance work for an agency. But the only opportunity that materialized was a full-time, year-long contracting role at a corporation you’ve definitely heard of. I accepted it, mostly because it paid way more than unemployment benefits and wouldn’t require relocating to San Francisco or Silicon Valley. Plus I figured getting out of the house every day would do me some good.

Of course, the downside of a full-time, year-long contracting gig is that you have all of the hassle of a commute, coworkers, and office life, with none of the benefits besides a pay check. I had the promise of a possibility of a full-time job if I busted my ass for 12 months. Plus most of the tech skills I’d pick up would be specific to the company. Since I didn’t feel passion for the organization or the work, the idea of having to prove myself for a “maybe” quickly lost its appeal.

But what bothered me most of all is that I was not making the same level of strategic and architectural decisions that I had grown accustomed to while working at Armchair Media or while freelancing. And over the two months I worked there, it became really obvious that the company’s technical direction would not leave me with much opportunity to make those decisions. They were moving towards a centralized front-end framework and a set of tools that were built at corporate headquarters in northern California. I realized that I probably wouldn’t ever get to do the kind of work I wanted to do, even if this magical carrot job did appear at the end of 12 months.

So I quit. I probably showed bad form with the way I did it, but it was so, so necessary, and I’m much, much happier for it.

What am I doing now? Well shortly before I quit, I formed a corporation: Webinista, Inc. It offers — well, I offer — “white-label” web development services for design teams and agencies. Yes, I decided to give the full-time freelance thing a shot. I’m even renting an office at WeWork Hollywood (which is a fantastic space full of small one-to-four person offices and small businesses).

I’m entering month three of full-time self-employment, and I’ve been lucky enough to have steady work that covers the bills. I’ve also promised myself that I would do this for no less than one year. Entrepreneurship is the culmination of a lifelong dream and I’m really excited to be on this path. I am doing work that I enjoy, with people I like, and on a schedule I get to set. I don’t think I’ve ever been happier.

]]> 0
Expected Identifier bug in Internet Explorer 8 Tue, 10 Sep 2013 12:00:55 +0000 Expected Identifier error dialog in Internet Explorer 8

While working on a client project, I ran into an error in Internet Explorer 8. That’s not the most helpful or descriptive error in the world, so I was a bit thrown for a loop. What’s more, a Google search didn’t turn up any clear answers.

The code in question involved a JavaScript object resembling the following snippet.

var products = [{
	'title':'Mary Had A Little Lamb',
	'price': 1.99
   	'title':'Twinkle Twinkle Little Star',

Further down in another function, the properties from the object were referenced somewhat like the example below. products, function(prod){
	var item = document.createElement('li'), frag = document.createDocumentFragment();
	item.className = prod.class;
	item.textContent = prod.title;
	frag.appendChild( item );
	document.getElementsByTagName('ul')[0].appendChild( frag );

Now expected identifier errors are pretty common. You’ve probably run into one before, and I bet one of the following things, outlined by Tobias Sjösten, caused it.

  1. There’s a stray comma after the last item in an object.
  2. A JavaScript reserved word has been used as an identifier (function or variable name).

The first cause doesn’t apply here. Neither of the objects in our array have trailing commas. We can rule that out. But what about the second cause?

JavaScript prohibits some words from being used as variable or function names. These include words like break, switch, and with that have special meaning in JavasScript. They also include a category of words known as Future Reserved Words, which do not yet have a special meaning in JavaScript, but could one day. These words include:

  • class,
  • enum,
  • extends,
  • super,
  • const,
  • export, and
  • import.

JavaScript allows almost any unicode sequence to be an IdentifierName. An object’s property is an example of an identifier name. Variables and function names, on the other hand, are two examples of an Identifier. Identifiers are kind of defined by what they are not, that is they are an IdentifierName with a character sequence that doesn’t match the Unicode value of a reserved word. The ECMAScript 5.1 specification explains some of this. Also read Mathias Bynens’ Valid JavaScript variable names for a better understanding of this.

Here’s where things get a little weird: class, the property name we’re trying to access, is one of the future reserved words on our list. But in the context in which we’re using it, it’s actually an identifier name. In other words: this shouldn’t be a problem. It isn’t for most browsers, including Internet Explorer 9+.

For Internet Explorer 8 (and presumably earlier versions), however, it is. IE8 treats our class property as though it’s an identifier even though it’s not. I think it’s actually expecting a variable name to follow class. Because none does, the browser chucks a wobbly. That’s a bug, and not the way things should work.

The good news, however, is that this only happens when using dot syntax. That makes fixing it easy: use square bracket syntax instead. Changing item.className = prod.class; to item.className = prod['class']; allows us to work around this bug, and doesn’t break things in other browsers. (The other solution, of course, is to change the property name.)

]]> 0
SitePoint HTML5 Experts chat transcript Mon, 09 Sep 2013 23:47:36 +0000 Being called an expert still makes me O.o. Frankly, I don’t think I’ll ever be comfortable with the label, even though I’ve been doing this for awhile, and kind of know what I’m doing.

That said, when SitePoint invited me to do an HTML5 experts chat last week, I said “Hey, why not?” and agreed. The transcript was posted a few hours after the chat, and because I’m horrible at brand management and self-promotion, it didn’t occur to me to write about it until today :-).

Talk with the Experts: HTML5 – The Transcript

]]> 0
Getting to know mutation observers Mon, 09 Sep 2013 12:00:52 +0000 I wrote another article for Dev.Opera about the MutationObserver interface, which is actually quite a bit of fun to use. It was published last Thursday.

MutationObserver is a replacement for mutation events, and essentially keep track of changes to the DOM tree: elements and attributes.

As always, please read it, and leave questions or raise issues in the comments.

]]> 0
CSS 3D Transforms on Dev.Opera Wed, 19 Jun 2013 03:25:51 +0000 Though I am no longer with Opera, I do plan to keep contributing to their Dev.Opera site. As part of the launch of Opera 15 beta for desktop computers, they recently published a piece I wrote about CSS 3D transforms. Have a read, and feel free to ask questions or leave comments on their site.

]]> 0