Building a centered gallery grid with flexible column count for responsive web pages

It took an untold number of fruitless Google searches and a couple of hours of trial and error to get this to work. I think part of the problem may have been that I simply didn’t really know how to describe what I’m trying to do in a way that would yield good search results. And so, I hope now that I have a solution, sharing it here might help someone else.

The situation: I have a web page that contains a gallery of square images. The page is responsive but the sizes of the images are fixed. I want the page to automatically show as many images across as will fit in the layout on any particular screen, creating anywhere from one to five columns as needed. And, it needs to stay centered.

I got all of this going pretty easily… all except the “it has to stay centered” part. I was able to get it to work if there was only a single line of images, but as soon as they wrapped to multiple lines, the container element went to a full width and the images became left-aligned. It took considerable effort to discover a solution, although that solution itself is embarrassingly simple. I was hung up on a couple of possible approaches that got me nowhere, which probably contributed to the problems I had finding the right way to do it.

So… here we go. We’ll start with an unordered list:

<ul class="gallery">
  <li><img src="image.jpg" alt="" /></li>
  <li><img src="image.jpg" alt="" /></li>
  <li><img src="image.jpg" alt="" /></li>
  <li><img src="image.jpg" alt="" /></li>
  <li><img src="image.jpg" alt="" /></li>
  <li><img src="image.jpg" alt="" /></li>
  <li><img src="image.jpg" alt="" /></li>
  <li><img src="image.jpg" alt="" /></li>
  <li><img src="image.jpg" alt="" /></li>
  <li><img src="image.jpg" alt="" /></li>
</ul>

And here is that embarrassingly simple CSS:

ul.gallery {
  text-align: center;
}

ul.gallery li {
  display: inline-block;
}

OK, that’s not really all of the CSS. Your li tag needs height and width properties, and you may want to give it margin as well. But those values are going to be specific to your project.

TinyMCE and the non-breaking space problem

Let’s get right to it then: TinyMCE is great, but I am annoyed by its willingness to take users’ multiple spaces literally! Collapsing multiple spaces is a basic characteristic of HTML, and allowing users to carelessly (or intentionally, which they still shouldn’t do) insert multiple spaces by converting every other one of those spaces into the &nbsp; (non-breaking space) character is BAD!

IMHO.

Anyway… start with a pinch of Stack Overflow, add a dash of the official TinyMCE documentation, along with a heaping tablespoon of reading between the lines, and I have a working solution to the problem. My installation of TinyMCE now automatically converts any &nbsp; characters in the text back into regular ol’ spaces.

It’s a bit draconian; after all there are legitimate uses for non-breaking spaces. But 95% of the times they’re inserted by TinyMCE are user accidents, and another 4.9% of those times are abuses like faked “tabs” that would be solved better by another approach altogether. (There are reasonable CSS-based solutions that work in some cases, but let’s talk HTML’s need for tabs another time.)

Anyway… here’s the gist of the solution. You need to create a callback function. Here’s mine:

function my_cleanup_callback(type,value) {
  switch (type) {
    case 'get_from_editor':
      // Remove &nbsp; characters
      value = value.replace(/&nbsp;/ig, ' ');
      break;
    case 'insert_to_editor':
    case 'submit_content':
    case 'get_from_editor_dom':
    case 'insert_to_editor_dom':
    case 'setup_content_dom':
    case 'submit_content_dom':
    default:
      break;
  }
  return value;
}

It may look like there’s a lot of extra stuff in here you don’t need; I included all possible values for type inside the switch to be prepared for the future. You do want to check for type == 'get_from_editor' though; otherwise your replace() is going to run under way too many conditions and may cause weird behavior like new paragraphs appearing when you just want to insert new text into an existing one, or browser-generated warnings about leaving the page when you try to save. (I ran into both as I was fine-tuning this.)

Now that you have your callback function, you just need to… you know… call it. That’s done inside tinyMCE.init(). You’ll need to include this line somewhere:

cleanup_callback: 'my_cleanup_callback',

Be sure to check if cleanup_callback is already declared somewhere, and also don’t forget the comma at the end, unless you’re inserting this as the last line.

Once you’ve got it all rolled out to your site, you’ll need to clear your cache. I’ve found TinyMCE’s configuration files can be annoyingly persistent in the browser cache.

Yes… you have correctly observed that I had to use non-breaking spaces myself in this post, to get the indents in the code samples to show. Pay no attention to the man behind the curtain. And remember my complaint about the lack of tab characters in HTML. Another day.

February 1983 / February 2013

The sting in my nostrils as I step out the back door
Into the pre-dawn cold

The smell of car exhaust mixing
With the frozen winter air

The stretching shifting halos
Around the streetlights seen through squinting half-awake eyes

The snow stomped from my boots before I step
Through the front door

Recruit THIS!

I have perhaps an unhealthy contempt for technology recruiters. I know they’re just doing their job, but it just so happens that their job is only slightly less annoying to me than telemarketers, or those people working mall kiosks who want to shove lotion samples in your face and yell at you for not accepting it.

Part of my distaste for recruiters comes from my own persnicketiness regarding tech jobs themselves. I love technology, but a lot of the ways it gets put to use are tedious and boring or even worse, objectionable to my values. (My primary values being avoiding things that are tedious and boring.) And there seems to be a strong correlation between tech jobs needing recruiters to find people to fill them, and those jobs being the kind of tedious, boring, objectionable work I wouldn’t want to take anyway.

I know I was lucky to have mostly worked at places I found interesting (or at least acceptable) during my decade or so of employment, and I’ve been even luckier to create a niche as a small business owner where my clients and collaborators are interesting, creative, and doing work I value in the world.

In short, I have no place in my life for recruiters or the jobs they recruit for, and never really have, save for a brief period in late 2007 when the job I was in at the time was turning sour and I was desperately casting around for alternatives. That one experience I had dealing with a recruiting company was so negative that I vowed never to work with one again. And as it happens, I’ve never even had to consider it, because I found a new job without their help, stayed there for a few months, and then successfully went out on my own less than a year later.

But occasionally I still hear from the recruiters. Usually (thankfully) by email. And I usually only give them enough of my time to reply “Please remove me from your database.”

Today I got just such a recruiter email:

To: Me
From: Recruiter X
Subject: update [sic]

Scott,

It has been a little while since we connected.

Just wanted to get a quick update on your status.

Thanks,
Recruiter X

I definitely did not recognize the sender’s name (and not just because it was “Recruiter X”), nor the name of his company. I was pretty sure it had been a very long while since we had “connected” — like, never. My reply:

To: Recruiter X
From: Me
Subject: RE: update

Please remove me from your database. Thank you.

I figured that would be the end of it. Surprisingly not.

To: Me
From: Recruiter X
Subject: RE: update

Scott,

Can do. I am guessing that you don’t remember getting together a few years ago.

Continued good luck with your business.

Sincerely,
Recruiter X

Why no, I don’t remember getting together with you a few years ago, or ever, Recruiter X. And I just couldn’t leave it alone:

To: Recruiter X
From: Me
Subject: RE: update

No, I don’t. Perhaps you could refresh my memory on the context of our meeting.

I honestly did not expect a reply at all to this message. What context could he possibly provide, since I know we have never met before? But I was wrong.

To: Me
From: Recruiter X
Subject: RE: update

It was at a time that you were looking for additional work. I believe it was as far back as 09 or 10, so I understand if you don’t remember. The intent was as an introductory meeting and to do some general networking. You shared your resume with me at that time.

I obviously am not looking to spam you. I was just looking to reconnect.

Sincerely,
Recruiter X

Oh, yes! That time I was looking for additional work! Way back in 2009 or 2010! Now I… no, wait. I still don’t remember. Maybe that’s because I haven’t looked for work with a recruiting company since 2007. In fact I haven’t even produced, much less distributed, a résumé since early 2008. And I had never heard of Recruiter X’s company. And, no offense, but I took a look at Recruiter X’s company’s website and… well… let’s say it did not strike me as the website of a company that would be good at placing people in jobs in web development.

Obviously…

I started drafting a snarky reply (yes, even snarkier than this post), but I elected not to send it. I think I had, and have, already proven my point. Which was that I might complain about recruiters wasting my time, but I am more than willing to waste that time myself in order to complain.

Postscript

On the extremely remote chance that “Recruiter X” happens to read this post… don’t take it personally. Just delete my information from your database. And from the databases of all of the other companies your company shares information with in exchange for money. Because someone gave you my information, but it sure wasn’t me. I don’t blame you personally for how annoying I find the business of recruiting to be. But since my information is a commodity to you, I also don’t have a lot of sympathy for your work.

The uncomfortable marriage of the UNIX command line and Mac GUI, and its implications for my sudoers file

I’m a longtime Mac user. A “power user,” you might say. Not so much a power UNIX user, though I do a fair bit of Linux-based command line tomfoolery as part of my job.

But things get ugly when the two come together. At the command line I am a bit too inclined to treat my Mac like a Linux server. It may have UNIX at its core, but it’s not Linux. And Apple has put some effort into de-UNIX-ing it as well. Things you expect to work don’t work the way you expect them to. (Yes, I just wrote that sentence. See what this is doing to my brain???)

For reasons I don’t care to get into, I decided today that I needed to modify the sudoers file on the studio’s Mac mini file server. And in my own inimitable and slightly stupid way, I handled this task as I typically do anything involving changing buried system files, not by struggling through using a command line text editor, but by copying the file to my desktop (where it is magically released from the prison of UNIX file permissions in which Apple has… uh… imprisoned hidden UNIX system files). I edited the file and put it back in the /etc folder where it belongs.

Only problem: in the process, the file’s ownership and permissions got changed. No problem, I thought. I’ll just sudo that sucker. Only problem is, when the permissions on the sudoers file aren’t what the system expects them to be, it doesn’t let anybody sudo anything.

Well… crap.

But then I remembered… Mac GUI solutions to the rescue! I opened up Disk Utility and ran “Repair Disk Permissions.” Problem solved! Apple has saved me from myself.

Now I can go back to my delusion that I am a power user.