TIL in JavaScript: Timers

Time is an illusion, and time in JavaScript doubly so.

This is the start of — hopefully! — a new series for me, “TIL in front-end web development.” In case you have never been exposed to it before, “TIL” stands for “today I learned.” I believe the term has its origins on Reddit, that wretched hive of scum and and occasional hilarity.

My purpose with this series is to chronicle what I’m learning in my personal front-end development enrichment projects — which I suddenly have a lot more time for, thanks to unemployment. I’ve been doing this work for 10+ years professionally, but I still learn something new every day; every day I’m Googling something I don’t know, or some topic I need a refresher on.

Some of the things I searched for while writing this blog post. I’ll leave it as an exercise to the reader which are related to this blog post, and which aren’t. “Lenticel,” for example: hot new JS framework, or part of a plant?

Without further ado, let’s talk about timers.

“Don’t lie, you’re crying because you have been coding (timers) in JavaScript.” Surprisingly few tears were shed in the making of this blog post! (The meme is CodeHub’s, but the red text is all me).

Brew tea as long as you want, as long as it’s five minutes

My most recent web development enrichment project has been Teamer, a tea timer webapp built using only HTML, CSS, and vanilla JS. Between that, and a code challenge I did for a job interview recently, I felt like I was thrown into the deep end of the “I write algorithms not event handlers” pool.

(“I write algorithms not event handlers” is clearly the next hit single from Panic! At the Disco).

Teamer started very simply, with just a series of buttons corresponding to each tea. When you clicked one, it would start a timer using the brewing time ceiling for that tea.

Like so. In the original iteration, if you clicked on the pale blue circle corresponding to white tea, you immediately started a five minute timer.

In this version, there was no possibility for adjustment. You wanted white tea, you got a five minute timer. That’s it. It wasn’t the most friendly user experience, but it was fine for a first pass.

(There are plenty of tutorials, Codepens, and JSFiddles out there about building a basic timer, but did I look at any of them? I did not. I knew I would learn it better if I had to figure it out myself).

The basic tea timing algorithm

Fundamentally, the timer algorithm is:

  1. Set the timer: set the visual display of the timer as minutes and seconds, and save it in milliseconds somewhere. (Where this value is saved varied between versions. Currently it’s stored as the value of the play/pause button). Logically enough, this is a function called setTimer();
  2. Calculate the starting time in milliseconds. This uses the Date.now() method, which returns the current time in UTC/Unix epoch format, i.e. the number of milliseconds since 12:00am, January 1st, 1970. (Why 1970, I don’t know; I don’t make the rules. Maybe one day they’ll give me Tim Berners-Lee’s private number and I can call him up in the middle of the night and ask him questions like this).
  3. Calculate the deadline — the point at which the timer will stop — by adding the milliseconds from step 1 onto the Unix start time from step 2.
  4. Start ticking: Using the setInterval() method, “tick” every second (1000ms) until the deadline.
  5. On every tick: update the visual display as well as the current milliseconds, and compare the current milliseconds to the deadline .

Once I had that working predictably, I decided it was time to break everything add some user controls.

User controls = extra complication

(Matt saw me writing that title and said, “You’ll soon learn that users are the enemy”).

For the next iteration, I wanted to add a few new buttons: play/pause (that would allow you to pause and restart the timer), stop (that would stop the timer and set it to zero), and buttons to increment or decrement the timer by one minute or ten seconds.

That’s when things got complicated.

For one thing, I had to separate some of the logic from setTimer() out into a new playTimer() function. Previously, the timer started as soon as you selected a tea; now, I wanted the timer to start only when the user hit the play/pause button. So this necessitated some refactoring.

This is also where I created tick(), breaking out an anonymous function inside setTimer()/playTimer() into a named function that I could run with setInterval(). This function was designed to hold all the things that had to happen each time the timer ticked down — everything in step #5 above.

Using a combined play/pause button also meant that I had to keep track of the toggle state of the button, which I did with a playing Boolean variable.

Incrementing/decrementing necessitated a probably-too-clever switch() block based on the value attribute on each increment/decrement button:

       switch (parseInt(btn.value)) {
            case 60:
                setTimer(mins+1, secs);
            case -60:
                if (mins === 0) {
                    setTimer(0, 0);
                else setTimer(mins-1, secs);
            case 10:
                if (secs > 49) {
                    setTimer(mins+1, (secs+10)-60);
                else setTimer(mins, secs+10);
            case -10:
                if (secs < 10 && mins === 0) {
                    setTimer(0, 0);
                else if (secs < 10) {
                    setTimer(mins-1, (secs-10)+60);
                else setTimer(mins, secs-10);

You can see that as well as resetting the timer, it handles some corner cases around converting from base 60 to base 10, i.e. when you reach 59, you need to roll over to zero, not 60. Also in there is logic to prevent you from setting the timer to negative numbers.

(I’m embarrassed to admit how long I swore at this switch() statement, which seemed to be doing zilch on my first pass — no timers were being set. Then I realized that the btn.value was coming in as a string, and thus it wouldn’t enter any of the cases — cases inside a switch() block always have to be integers. JavaScript’s wibbly-wobbly typing strikes again!)

Feeling self-satisfied with my work, I pushed my code to my website and added it to Codepen. But then I noticed two other problems…

Take one down, pass it around… three gnarly Javascript bugs on the wall!

The two three problems are found were this:

  1. The timer was occasionally displaying as “:60” instead of “:00.”
  2. Adding time to a timer while it’s running causes the timer to become All Fucked Up (a technical term).
  3. Remember #1?…

The importance of being earnest (to the rounding method you choose at the start)

Debugging problem #1, I quickly realized it had nothing to do with the tortuous switch() block — that was your first thought, too, eh?

However, I was concerned by the logic to calculate the remaining time on a timer — part of the tick() function, called every 1000ms. It looked something like this:

       if (end > now) {//time hasn't elapsed yet
            let diffMs = end - now;
            let diffMin = Math.floor(diffMs / 60000);
            let diffRemSec = Math.round(diffMs % 60000 / 1000 );            
            setTimer(diffMin, diffRemSec);         

(It actually wasn’t nearly as neat, because at this point I hadn’t yet figured out how to use the modulo operator to remove the minutes I had already accounted for. I highly recommend this Stack Overflow answer for the smarter way of doing things).

(Also no idea why I’m using let for those three variables that I’m never reassigning. I guess I’m still not 100% used to the ES6 assignment keywords).

You may notice this disconnect between the Math.floor() method I’m using for diffMin and the Math.round() method I’m using for diffRemSec. Surely that may cause some weirdness, right? Plus there’s nothing stopping from Math.round() from rounding up to 60; I’m not doing any base-conversion math like I am elsewhere. I also couldn’t remember why I had chosen Math.round() instead of Math.floor() — so, ultimately, I changed it to Math.floor().

Good news: I no longer saw “:60” instead of “:00”.

Bad news: the timer was now skipping numbers. (This is bug #3, alluded to above). Most noticeably, when you started the timer, it went straight from “:00” to “:58.” It would also occasionally skip numbers down the line.

I tried a bunch of different solutions for this. Applying one Math method, then another (no dice). Testing for that “:60” case and manually resetting it to “:00.” (That caused a slew of other issues). None of these really did what I needed them to do.

The basic problem was: it’s correct to use Math.floor(), but the visual display of that data is incorrect.

Time is an illusion, and tea time doubly so.

Having ruled out rounding error, the conclusion I came to regarding the cause of the skips was: the code in tick() took some non-zero amount of time to execute. Thus each measurement was being taken at 1000ms + 5? 10? ms, which over time would lead to drift.

Alternately — or in addition — there’s the fact that setInterval() is cooperatively asynchronous. That means all synchronous code on the main thread must clear the call stack before the setInterval() callback executes. (Hence the source of Every Hiring Manager’s Favorite JavaScript Question Ever).

Give that, I asked myself: can I run tick() more frequently?

Before I dive into that, allow me a minor digression to talk about metaphors. (What can I say, I’m a word nerd as well as a nerd nerd).

The concept of a “tick” comes from an analog clock with hands, where each second is a movement of the hand of the clock, making a click or tick noise. If you speed up the ticks of an analog clock, you get a clock that runs fast; it will ultimately become so out of sync with Observed Time ™ that it becomes meaningless.

From my trip up the clock tower of Bath Abbey when I was there in November 2019. We were warned extensively not to touch the 18th century clock mechanism, as there was a very real risk of changing the time for the city of Bath.

But that metaphor doesn’t transfer perfectly to our timer, does it? If you speed up the ticks, all that happens is the display is updated more often.

“Really, Lise?” Really. I know it doesn’t sound right, but bear in mind — what ultimately determines when the timer ends is the deadline in milliseconds. That never changes, no matter what you do on each tick. And both the deadline and the current milliseconds are grounded in Unix time, which is as official as it gets.

So what’s left? The visual display. There’s real math happening behind the face of this clock, so the updates will always be accurate to the current Unix time. But if the user sees skips in the sequence, they’re not going to trust that it’s accurate.

Here’s where I’m practicing my UX design skills. Because the conclusion I came to is:

  • What’s most important to the user experience is the illusion that the timer is counting down at a rate of 1 second per second, with no gaps.
  • The human brain can’t tell the difference between 1000ms and 990ms.

So that’s what I landed on — tick() is run every 990ms instead of every 1000ms. Like so:

ticker = setInterval(tick, 990, deadline);  

Relatedly, I want to take a moment to add: making setInterval() a function expression in the global scope is crucial, so that you can use clearInterval() to stop your timer. The assignment snippet above lives in playTimer(), but it’s first declared near the top the JS file with let ticker. (See, that’s the right usage of let!)

Anyway, I tried a few different intervals, but I still saw skipping with 999ms, and with numbers below 990, I often saw flashes of the same number twice (as the display was updated with an identical number).

(You will see those once in a blue moon even with 990ms, but it’s not super noticeable. If I decide to add a CSS transition to the numbers, I might have to account for that — maybe setting up a control block that only updates the number if it’s different from the immediately previous number?)

Once again, JavaScript allows me to pretend I’m a Time Lord.

Who does number two work for?

I didn’t forget bug #2 (inc/decrementing a timer while it’s running causes weirdness), I promise! Although I did set it aside temporarily while I dealt with JavaScript’s timey-wimeyness.

I found there were a couple of things going on here:

Problem the first: the deadline was not being updated to reflect the new deadline. When you added/removed time without going through the click handler on the play/pause, you were never invoking playTimer(), and thus never setting a new deadline. So if you added a minute to a 3-minute timer, it would look like a 4 minute timer, but in the code it was still waiting for a time three minutes in the future.

So, I should explicitly invoke playTimer() after my big ol’ switch() block, in the click handler for the increment/decrement buttons, right?

But hold on, what if the timer is already paused? Then I’d be doing it twice; once at the end of the block and once when the play/pause button is clicked. I definitely don’t want to set the deadline or change the playing state twice.

So this is was my first iteration:

        if (playing === true) {
            playTimer(); //if timer is running, run playTimer() to update the deadline; otherwise it will update when the play/pause button is clicked again

That fixed the “resetting the deadline” issue, but in classic debugging fashion, raised a new problem: now the timer would flash between the old time and the new time. Wtf?

I eventually figured out I had to stop the ticker (with clearInterval(), in the stopTicker() function) before starting another one. I’m guessing this is because every time you run playTimer(), you create a new instance of ticker; they each have their own closure with the same starting values, but then they diverge based on the differences in the environment at the times they’re run. You get the flashing behavior because the two different tickers are trying to modify the same DOM element, like two children fighting over a toy.

… but my understanding of the inner working of JavaScript and closures is imperfect, so take this analysis with a grain of salt.

Anywho! This worked fine:

        if (playing === true) {
            playTimer(); //if timer is running, run playTimer() to update the deadline; otherwise it will update when the play/pause button is clicked again

In Conclusion: What I Learned

I’ve finished all the time juggling for my tea timer app (for now, she says, ominously), and now I’m working on adding more features. An alarm when the timer ends? Using localstorage to allow users to add custom teas? Heck, maybe I’ll even add the ability to have multiple timers running at once, as an excuse to work with classes in JavaScript.

But to summarize what I learned about timers in the process of writing Teamer:

  • Date/time math is easier with modulo.
  • User control makes everything more complicated.
  • Sometimes the answer to “why doesn’t this razzlefrazzle work?” is “you need to parse it as an integer.”
  • Be consistent in your rounding methods, and always use Math.floor() when working with time.
  • If you want to stop your setInterval(), you need to tie it to a function expression in the global scope.
  • Just because your timer is meant to update every second, doesn’t mean it needs to update at precisely that interval — the illusion is more important than the truth.
  • Honestly, timers are a solved problem, and if I were doing this for any purpose other than my own edification, I’d probably go with the time-tested approach of copying and pasting from Stack Overflow.
I never run out of uses for this image.
  • I still maintain that working with JavaScript is like being a Time Lord — you get to work with a lot of wibbly-wobbly timey-wimeystuff.
  • I wanna meet someone who was born at midnight on January 1st, 1970, just so I can give them the nickname “UTC.”

If you want to see the current iteration of the code with highlighting ‘n stuff, it’s up on Codepen.

And that is already way longer than I ever intended this post to be. Hopefully it is useful to someone other than future!Lise.

Lise is a free elf! (or: I lost my job)

Photo by Andrew Neel on Unsplash

Here we are, six months into 2020, and hooboy, it sure has been a century. It feels irresponsible to start any personal blog post without an acknowledgement of COVID-19, the increasing fascism of the U.S. government, and racial injustice.

So before we launch into the latest episode of The Adventures of Lise: Transtemporal Gadfly in the Year 2020, let’s take a moment to acknowledge that there’s a whole big world out there that has nothing to do with my personal struggles.

(In case you have any doubt where I stand on current events: Black lives matter. And since it’s also Pride month: Black queer lives matter, and Black trans lives matter. If you have opinions contrary to that, you are welcome to keep them to yourselves and/or fuck right off. If you want to clutch your pearls about me expressing that opinion on a public post where an employer might see it, you are also welcome to get lost — I don’t want to work for a company that would judge me for fighting injustice).

… okay, ready to go on?

The big bad news: job loss

On May 12th, I was laid off, along with most of my team. It was very abrupt, very surprising — and yet inevitable, in retrospect.

It was made clear to me by many people that this decision had nothing to do with my performance, and everything to do with company financials. As far as I know, my manager had nothing to do with the decision — it was all made at a higher level based on I-don’t-know-what criteria.

My immediate reaction was… ambivalence. You see, I had already been looking for a job, on and off, for the past six months. I had been at this company ten years and I felt like I was stagnating. I had a few promising interviews in late 2019, but nothing panned out. So at first I was like, hooray, an opportunity to do something new?

But as the weeks have gone on, I’m definitely found a trove of… sadness? Nostalgia? about the loss. Even though I was ready to leave this company, it’s hard to put the work of ten years behind you in a day. I think of all the people I probably will never see again — my amazing manager and team members! — and the places I’m unlikely to return to (like the Savers of Framingham, or the Cochituate Brook Rail Trail). Sometimes I even think nostalgically about sitting at a certain traffic light on Speen Street.

Plus, we had all been working from home for two months due to the pandemic, which made being suddenly cut off particularly traumatic. I had (and still have!) a bunch of my personal belongings at the office. Going into an empty office to reclaim those tomorrow is going to feel exceptionally weird.

The good news is that we are not being left without resources. I have access to severance, outplacement funds, benefits continuation, etc, which means that for a few months, I won’t have to worry about paychecks or health insurance and I can focus on finding a new job. The economic situation is dire, of course, but I honestly feel like I’m in a better place than I was with my job loss in 2009.

In the final account… I’d rather be one of the people let go than one of the people remaining.

What kind of work do you do, anyway?

I’m in front-end web development, meaning I work primarily with HTML, CSS, and JavaScript (and adjacent technologies). My title before I was laid off was “senior front-end developer.” I have ten years of experience working on websites for a major tech publisher, plus additional freelance and personal experience. I’m happy to forward my resume if you think you have something that I’d like.

What am I looking for next? One word: values

First thing to know about me: I am fundamentally pessimistic about employment. I am always aware that you can be let go from any job, at any time, for any reason; there is no such thing as job security. You are only valuable to the company so long as you make it money. Capitalism gonna capitalize.

But I’m less capable these days of being blasé about that. Watching the news, I hate seeing incompetent executives — who are usually old white dudes — steer their companies towards disaster in the search of 100% year-over-year growth. (Patreon, I’m looking at you). I hate to watch billionaires like Jeff Bezos and Bill Gates do nothing* when they have the power to stop a pandemic in its tracks without even sacrificing 1% of their wealth.

*(or “very little, and only on their strict terms”)

I don’t want my next job to feel like I’m just a replaceable cog in a machine of death. I don’t agree with the corporate philosophy that “if you’re not growing, you’re failing.” I think more things matter than the bottom line.

Thus it’s important that my next position be at a values-driven institution.

Maybe that’s a non-profit, or a university. Maybe that’s a company that has a mission statement that it takes seriously, and which is is alignment with my values.

At the end of the day, I need to feel like I am more than just a machine for spitting out front-end code, or some kind of modern-day Morlock.

That may lead you to ask…

“…what are your values, anyway, Lise?”

You probably get a good sense of it from reading this whole post, but to list a few words and phrases that come to mind:

Intellectual curiosity.



Fairness. Accuracy. Equality and equity. Social justice.

Compassion. Treating people as ends, not means.

Putting people’s lives above property.

The power of stories.

… and probably more. Developing one’s values, after all, is the work of a lifetime.

What else is important to me in my next job?

Unlike the previous consideration, the points below are all negotiable — I’m willing to do work that’s less in alignment with my interests if I can do it remotely; I’m willing to go into an office some of the time if I can solve interesting problems. I’m also willing to be flexible on pay and benefits if I can do work I love.

I want to work remotely.

I live in rural Massachusetts, and I am 50 miles from the nearest big city (Boston). Let me just say, I do not want to work in Boston. I’m not even sure I want to commute to Worcester, some 30 miles away.

Since I had been doing my job remotely for two months, and working remote regularly before that, I see no reason why I need to go into an office.

Generally I feel that the managerial attitude that wants to see “butts in chairs” is the same attitude that values the appearance of productivity over actual results, and I will take a hard pass on that attitude.

I want to solve problems.

All my performance reviews at my last job said the same thing: “Lise is a tenacious problem solver.” I’m happiest when I can be fully immersed in Making Something Work.

And when I succeed in solving a problem? Man, there’s nothing like that rush. It’s true for writing and it’s true for web development — although when I come up with a different way to use aspect-ratio CSS cropping, the audience to whom I can brag is considerably smaller 😉

Arguably, all technical work is problem solving, so this doesn’t really narrow it down, does it? So let me further qualify: I’d like to solve interesting and important problems.

First, the interesting. I’d like to get better at writing novel algorithms. So much of web development is trodding the same ground over and over again; it’s hard to find opportunities to come up with a new approach from scratch rather than just copying and pasting a solution someone else has figured out. (Even if that someone else is “past you”).

“Essential Copying and Pasting from Stack Overflow: Cutting corners to meet arbitrary management deadlines.” It’s a joke, but like any good joke… there’s a kernel of truth to it.

Second, the important part. This is a value judgment, and I’m pretty flexible about this. For example, maybe entertainment isn’t “important” in some people’s eyes, but would you have done as well over the past pandemic months without books, movies, or RPGs?

Basically I don’t want to be working in an industry that takes away from people’s lives. I don’t want to be doing web development for ICE, or trying to sell people expensive products they don’t need, or working on a gambling site.

I want to work with modern(ish) technology.

I’d gotten kind of bored with technology stack at my old company, which had over a decade of momentum in the form of legacy code. We were still using JQuery and a bunch of other increasingly-obsolete technologies. It got to the point where every time I needed to update one of our tools, I went to the product’s website and was told “[Product] is deprecated!”

Also, I was starting to get complacent, and forgetting how to do simple things like “change a class name on a DOM element” without using JQuery.

I’d like my next job to be different in that regard.

Vanilla JS, thanks to ES6, is pretty great again, so I look forward to doing more with that. I’m definitely much stronger than I used to be in this regard, but every day I still learn something new. (Maybe I will start a blog series of “what I learned about Javascript today?” But that could just be an ADHD fantasy).

As my former manager and teammates would attest, I love burning cruft to the ground and starting over new, so I’m your gal if you want to rip out an obsolete product and replace it with something new. Like, say, ripping out JQuery.

(I seriously don’t hate JQuery, I promise. It was very good to me at a time when vanilla JS was not — when you had to write a helper function just to select a DOM element by class name. It was my gateway into JS, and I wouldn’t be the programmer I am now without it. But now that Javascript and modern browsers are catching up, it’s much less necessary than it used to be).

JavaScript frameworks are a Thing now, and I’d like the opportunity to work with one of those, if only to develop that skillset. (I’m pessimistic that any of these will stand the test of time — same as JQuery — but right now they are the Hotness). I have a slight preference towards React, because I’ve done some coursework with it, but I don’t know enough about the strengths and limitations of Angular, Vue, etc to have strong preferences yet.

I want a salary and title in line with my skills and experience.

I have at least 11 years of professional front-end web development experience. I have many more years of personal web dev experience — arguably, ever since I picked up The HTML Quickstart Guide in 1996 and started building my first website.

(I still have that book, mostly for nostalgia purposes. Occasionally I get a chuckle looking at its discussion of image maps, or the flyout of web-safe colors).

Without talking numbers, I was underpaid at my last job, so I am hoping to double my current salary, to bring me in line with folks doing similar work.

Likewise, I was a senior front-end developer at my last job, so I’m looking for a more senior position now. I’ve reached the point in my career where I have more web development Opinions than Questions, and I enjoy teaching and mentorship, so I am hoping that points me towards a Lead Front-End Developer position.

But no matter where I am, I believe in leading from the seat I’m in.

What don’t I want?

I’ve alluded to some of these already, but let me be explicit about what I don’t want.

I don’t want to relocate.

I’m 40 years old and I have a husband, a mortgage, and three cats. I am not interested in moving to Podunk, Idaho for a three-month contract as a full-stack developer on WordPress sites.


I’m not looking for contract work.

This may change if my severance period draws near and I become desperate, but for now, I am solely interested in full-time work.

In my last stint of unemployment in 2009, I found the primary benefit of contract work to be the professional experience it provided — otherwise, it disqualified me from unemployment and kept me from working full-time on my job search. I have no dearth of professional experience now, so the benefits are minimal.

I’m not a full-stack or back-end developer, or a designer.

I can sometimes play a full-stack developer — I can Google an API and muddle my way through a back-end language, and I’ve been known to modify a Java class or two.

But I am rubbish at knowing what looks good on websites. Some of that is teachable, but there’s an artistic element to web design that still eludes me. It’s important work, but not work I can do.

The middle ground I’m not sure about is UX (user experience; also known as UI, user interface). Some jobs consider this to be part of design, and some consider it to be front-end development. Generally, the more code-based the position is, the better I am at it. While I can tell you, for example, that Clear User Inputs Are A Good Thing — and implement them — if you want me to create a comp in Invision or Adobe XD, that is beyond my skills.

As I say on my LinkedIn profile, “I’m experienced at turning a designer’s vision and a back-end developer’s data structures into a functional, usable website, using HTML, CSS, and JavaScript,” so at the end of the day that’s what I’m looking to do more of.

I don’t want to work in Boston.

Or Cambridge, or Somerville. If it’s a remote job with a few days a month in the office, I can handle that, but making that commute on a regular basis will just crush me.

I will not take your timed, automated code test.

I have a whole rant about this, Forthcoming, Maybe, but let me just say: there are a host of reasons I hate these tests, delivered by third-party sites such as Triplebyte, Codility, or Testdome. But fundamentally it boils down to: these tests are discriminatory and non-inclusive, and don’t tell you anything about my strengths and limitations as a programmer.

I refuse to be assessed using them. Even if I did well on them — which I generally do not, because who can design an O(N) algorithm in 30 minutes with secret unit tests and alarms going off at regular intervals? — a company that uses them is probably not a company I want to work for. It suggests you don’t know what it takes to be a good coder and that you probably have an engineering team full of privileged white boys.

I will happily spend my entire weekend working on a take-home, untimed coding challenge for a company I like. (Heck, it’s what I spent last weekend doing). But I will not do a 2.5 hour automated, timed test for a company I just met, because it tells me everything I need to know about their values.

And that is: nothing good.

Relatedly — since the field of tech recruitment is a whole minefield of “what not to do,” whiteboard coding is also awful (though I wouldn’t turn down an interview that involved it), as is asking candidates riddles and brain teasers. My ability to solve the Monty Hall problem — or my, yanno, having heard it once already — tells you nothing about my ability to code, either.

If you feel the need to ask me to prove my coding skills — which is a fraught assumption, but let’s not get into that right now — please have your coding test be something like what I would actually be doing in that job.

I don’t want to work at your old boys’ club

Diversity in programming is really important to me — especially now, and especially given all the work STEM does to keep women, POC, and other marginalized sorts out of the field.

So if your company doesn’t have women and POC in engineering and in leadership positions — if your company signature doesn’t include your pronouns along with your title — give me a miss.

I will not be evil.

Like I said above, I’m uninterested in working anywhere near the carceral system. I’m uninterested in working for Facebook, Amazon, Google — even if I could pass their impossible coding tests, which I can’t. Finance and healthcare are also iffy for me — depends a lot on what corner of it they work in. I’m wary of VC-funded companies and I’m wary of family-owned companies, for similar reasons.

But mostly…

I don’t want to end up in a shitty job

Not that my last job was shitty — far from it. I have worked at shitty jobs, however, and let me tell you — they are a vortex.

Bad jobs suck you in, distort your worldview, and kill your hopes and dreams. Just getting through the day takes so much emotional labor that you have no energy left to look for better work.

(Heck, even good jobs have a kind of inertia. Hence: staying at my last job for ten years, which is generally a maladaptive strategy in this field).

I have been in the position of being forced to stay at a bad job for the money, and I never, ever want to be there again. I’m old enough that I’m starting to think about legacy (and not just legacy code!), and ultimately, I want my work to be a reflection of who I am.

In closing

… I just realized my title is a Harry Potter reference. We’re all aware J.K. Rowling is a transphobe, right?

But as Daniel Radcliffe — aka the actor who played Harry Potter in the movie adaptations said — in a statement for the Trevor Project, “if you found anything in these stories that resonated with you and helped you at any time in your life — then that is between you and the book that you read, and it is sacred.”

So allow me this mental image of me walking away from my old life, clutching a sock.

Lise’s HTML/CSS pet peeves, part 3 of 4: misuse of the !important flag

Remember these posts? I’ve been holding off on posting #3 because I realized I didn’t have as much as I thought to say about “nudging” with absolute and relative positioning. I would much rather talk about misuse of the !important flag. So, slight change of plan: I’m going to do that first.

Lise, what the hell is !important?

Not, in fact, a philosophical question.

If you’re a hobbyist CSS-slinger working mostly with your own code, you might not have ever heard of the !important flag. It’s the kind of thing that only really becomes relevant in large stylesheets, and usually only those touched by multiple developers.

I still recall, with something less than fondness, the first time I saw it. I was contracting as a front-end developer at a company that really wanted me to also be a designer and a back-end developer (for $30/hour — ha!) At first glance, I thought it was some sort of comment, like “this is important, do not delete.” I had to look it up.

What !important does, if you are unfamiliar, is move a CSS attribute to the head of the cascade.

So what’s the problem with it, Lise?

!important is kind of like a pushy jerk cutting in line, breaking the order which is the core of, you know, cascading style sheets. This is kind of a nuke-like power, and so it is important to use it sparingly.

So you say. Can you give me an example?

Let’s say you’ve just realized, after writing a bunch of CSS already, that you want ALL the <p> tags on your page to have a font-size of 15px, rather than setting it individually. You might write a style like this:

p {

As it happens, you also have a div called .box that has <p> tags inside of it, and you look to see that *gasp* these paragraphs are not obeying your command. They have a font-size of 14px, even though you said, right there on line 101, that all <p> tags should have a font size of 15px! This must not stand! You “fix” this by applying the important flag:

p {
	font-size:15px !important;

Whew. Problem solved, right? Your paragraph has a font-size of 15px, everyone is happy.

But… what you may not have realized is that, somewhere lurking in your stylesheet, there’s a style that says:

.box p {

… which you have just knocked over and taken the lunch of. Someone else — or an earlier version of you — has decided that paragraph tags within .box get the font-size of 14px, and you have just shot that style right in the head.

And? So what, Lise?

What happens if someone wants to override this style for another set of .box p elements? They will need an !important tag to override THAT style.

In a long enough stylesheet, you end up with an escalating war of the !important tags.

If this doesn’t seem that bad to you, imagine working on thousands of lines of CSS, much of it written by other people — which is what I do every day. The temptation in that instance, when your precious style is being overridden by something unwanted higher in the cascade, is to pull the pin on the !important grenade. It’s this use case:

  2. (use !important rule)
  3. OK, now it’s working

“When Using !important Is the Right Choice,” Chris Coyier, css-tricks.com

And yet, this is exactly the sort of place where you should not do this.

All right, I’m beginning to see. So what should you do instead of applying an !important flag and breaking the cascade we all know and love?

Some options:

You can change or get rid of the style for .box p. Not always possible, but if you are the only front-end developer working on a project, you can refactor all you like. (Oh, for that kind of freedom!)
– If what you are trying to accomplish is: “All paragraphs have a font size of 16px, except for the ones inside of .box… oh, except for this one example,” the best thing to do is to work with the cascade by making a more specific style. Maybe you want a special sort of .box, a callout box, to have a larger font size. So you set:

<div class="box callout">

And then set a style of:

.box.callout p {

(This is also an example of modular CSS, which I like).

Cascading makes my head hurt.

Here’s a rule of thumb: the longer the style declaration, the more specific it is. Everytime you add a selector, you make it more specific.

Is there anything !important is good for?

!important is very useful for overriding styles you don’t want that come in from sources you can’t control, like inline styles on social media sharing buttons. Have no compunction about overriding Facebook’s shitty JS-applied inline styles for its Like button. It won’t hurt Zuck’s feelings any.

Go back to: Part 1 | Part 2

Lise’s HTML/CSS pet peeves, part 2 of 4: clearer divs

This post is about another of my front-end web dev pet peeves: clearer divs, and associated float/clear madness.

(For those of you not webbily-inclined, we are not talking about what happens when you flush the toilet. It is — slightly — more pleasant than raw sewage).

Clearer divs fit under the category of “extraneous markup”, but I’ve given them their own bullet point because they INFURIATE me. Seriously, seeing a document riddled with this:

<div class="clearfix"></div>

Or worse yet:

<div style="clear:both;"></div>

…is enough to send me into a raaaaaage.

To explain the annoyance factor here, I need to explain a little about floats and clears for the front-end web dev n00bs in the audience. Most website layouts these days are based around multiple <div>s made into columns by applying the style “float:left” or “float:right” to them. Take this bit of markup:

#box {
#left_column {
#right_column {
<div id="box">
   <div id="left_column">This is the left column</div>
   <div id="right_column">This is the right column</div>

The content within those <div>s will form themselves into two rudimentary columns which continue down the page indefinitely. Like this:

This is the left column and it goes on for as long as you have content to fill it
This is the right column and because it’s wider it can go on longer and longer and longer and longer and longer

Unfortunately, it’s that indefinitely wherein the problem lies. Elements that come after those two columns will continue to contort themselves to accommodate that float, unless you tell them otherwise. This can cause a number of strange behaviors that are boggling to CSS newbies — the source of 90% of problems when my friends come to me with their webpages and say, “You know CSS; make this work!”

“But Lise!” you say, “your two columns above aren’t have any problems.” Well, that’s because I have cleared them. If you know your way around Firebug/Chrome Dev Tools, try toggling off the style on #box. You’ll see something like this (picture):

Screen Shot 2014-10-02 at 6.58.57 PM

So floats are tricksy, like hobbitses. But they can be countered by the clear CSS property. I like to think of an element with “clear:both” on it as CSS Gandalf, spanning the width of the parent element and saying “None shall pass!”

… I’ve just compared balrogs and hobbits. This LOTR analogy is breaking down, so let’s leave it aside. Will miss pointy hat.

The easy, ugly way to clear a float is to put a new, empty element after it — within the parent element — with “clear:both” applied to it:

#box {
#left_column {
#right_column {
.clear {
<div id="box">
   <div id="left_column">This is the left column</div>
   <div id="right_column">This is the right column</div>
   <div class="clear"></div>

This will do the trick — your successive content won’t try to jump up into #box.

So what’s wrong with it?

Well, it’s non-semantic and extraneous markup, which we’ve already talked about a little. That <div> isn’t pulling its weight; it has no meaning on the page, and exists only for appearance reasons — rather like a Wodehouse protagonist.

Moreover, there are a bajillion (okay, five or so) other ways to clear floats (more) semantically. To name them:

Floating the parent (in this example, #box). Floated parent elements will expand to contain floated children. Understandably, this doesn’t work everywhere; you may not want that element to jog to the left.

Setting overflow:hidden or overflow:auto on the parent. This is the method I used above to wrangle our columns. Like with floated parents, elements with overflow:hidden on them will expand to contain floated children. It has a few cons to its use, however:

  • It’s not supported in IE7 or below. But none of us are supporting that any more, right
  • overflow:hidden interacts weirdly with box-shadows
  • Obviously, if you need a different value for the overflow property, this won’t work for you

That said, I find a lot of use for this one, and it tends to be my go-to clear method.

Set clear:both on an existing (unfloated) semantic element that follows. Here you’re doing what you’re trying to do with a clearer div, on an element that would be on the page anyway. Dependent though it is on a very specific structure, this method is worth mentioning because this is common way of building a two column layout — float one div left, float one right, and have a footer that spans the document beneath it. Put clear:both on the footer and you’re good to go.

The so-called easy clearing method (warning, dated), where you apply clear:both to an empty space inserted into the DOM via the :after pseudo-classes. I didn’t use this one for a long time, due to lack of support in IE7 or lower for these pseudo-classes. It’s also a tetch non-semantic. But with IE7 being phased out more globally, it has become the most generally applicable method of clearing something — all the previous methods only work in a subset of cases.

A slight improvement on this is the micro clearfix. If you use Sass with Bourbon, it’s the method you get if you use @include clearfix().

(And this is why I’m a front-end web developer — so I can say my job involves sass and bourbon).

One troubleshooting hint: if you’re seeing odd behavior on a page, and floats are involved, try inspecting the parent element in Firebug or Chrome Dev Tools. (You are using these, right?) If it appears with no height, and on selection doesn’t appear to wrap its child elements, there’s likely an uncleared float somewhere in there.

That’s enough info, right?


All right, all right. I will acknowledge there may be corner cases where you have to stick clear:both on a piece of markup that wouldn’t otherwise exist. But I have only rarely come across such cases.

In case this rant didn’t help you to understand floats and clears, I point you towards a couple of my favorite resources. They are both a few years old, but — aside from the browser bugs — floats and clears haven’t changed much in ten years.

Next time, HTML/CSS bugaboo #3 – “nudging” with absolute and relative positioning.

Lise’s HTML/CSS pet peeves, part 1 of 4

I’ve been a front-end web developer full-time since 2010, but I’ve been playing with HTML and CSS since 1997. I remember the paradigm shift from tabular layouts to CSS positioning. I remember IE for Mac. I recall the dark days before Firebug and Chrome Developer Tools. I remember *shudder* the <blink> tag.

And in that time, I’ve seen a lot of bad code*, mang.

In particular, there are four things I see again and again that bug me. They are newbie goofs, or they are the kind of things non-specialist** developers do. They are common mistakes which I guarantee I made a metric shitload of when I was first starting out.

I only hope that by sharing this, I can save you some time 🙂

The four pet peeves I’m going to address in four posts are:

  1. Extraneous markup
  2. Clearer divs (and general float/clear madness)
  3. Over-using absolute/relative positioning for “nudging.”
  4. Over-using the !important flag.

Let’s get right to the first one: Extraneous markup

This is rather broad, but let me give you an example, based on something I see a lot in my job:

<div id="box">
   <a href="#">
      <p>line 1 of text</p>
      <p>line 2 of text</p>

The purpose of this markup is to make a link that spans multiple block-level elements. This is not default behavior for a link–<a> tags are inline elements by default in most browsers–but it is possible and a common need. <div>s on the other hand are block-level by default. In essence you’re making the link block level by wrapping it in a block-level element.

It works, but you have to make sure the link expands to fill the <div> so the whole block is clickable, being sure to account for padding, etc…

… or you could just make the <a> block level. Seriously. It’s one line of CSS: display:block;. Just do it, and can the <div>. It gives you this slightly neater HTML:

<a id="box" href="#">
   <p>line 1 of text</p>
   <p>line 2 of text</p>

(I just did a test in Chrome, and it looks like these days you don’t even have to set display:block; on the <a>. I’m pretty sure this was not always the case).

Other things that get my goat:
“Spacer” blocks, i.e. empty elements that exist only to add space to a site design. Remember those days before CSS borders, when creating a vertical rule was hard? This is no longer the case! These days we have margin and padding and borders and outlines, and we should use them.
Elements with no styles applied to them. If a tree falls in the forest and no one is there to hear it, does it make a sound? If an element has no styles attached to it, can it really be said to live at all?
non-semantic markup in general, i.e. things like <p class=”red”>.

That’s all for now, but the next post deals with my favorite (not really) non-semantic markup bugaboo: clearer divs.

* I used to be pedantic about not calling HTML/CSS “code” because it’s not procedural. But a) I am softening in my old age, b) I also write JS these days, too, so I can get away with it.
** Unsolicited opinion time: I think “full-stack development” is getting to be a worse and worse idea every day. The body of knowledge in front-end development has become large, and I think it’s unrealistic to expect someone who’s spent their career hacking at C++ to have a thorough understanding of floats and clears, the cascade, and cross-browser quirks.