An even dumber workaround for how dumb CSS hyphenation is

Look, it’s all well and good that CSS has a hyphens property. The problem is, that property is really dumb. It’s all-or-nothing, with no rhyme or reason to whether a word absolutely needs to be hyphenated. It will literally hyphenate any and every multi-syllable word at the end of a line.

You really almost never want that.

In my particular case, I’m looking at a very specific situation. Specific, but I am guessing probably the most common situation where a web developer wants a browser to hyphenate words: words in large headings that are too long to fit on a line. What I mean here is individual words that are by themselves too long to fit on a line, typically in a mobile browser, in headings with large or extra-wide fonts.

There are proposals to improve this, but there is currently nothing with broad browser support. So I invented my own.

This is a crafty little combination of CSS and JavaScript. (OK, technically it’s jQuery, but you could reasonably adapt this to vanilla JavaScript if that’s your thing. Since I’m deeply immersed in the jQuery world of WordPress, I just went with jQuery because it’s simpler for me that way.)

The first thing you need is a special CSS class for hyphenation. Since I only want it to apply on mobile devices, I gave it a logical name, and defined it in my CSS media query for the mobile breakpoint:

@media screen and (max-width: 782px) {
    .hyphenate-on-mobile {
        -webkit-hyphens: auto;
        hyphens: auto;
    }
}

OK, with that set up, then we just need a little jQuery function to determine where it’s going to be applied. I want it to get added automatically to any h1, h2, h3 or h4 tag. (I’m skipping h5 and h6 because they’re small enough text that we shouldn’t need it.) I also made the somewhat arbitrary decision to set the minimum word length at 15 letters. This is something you may need to adjust based on your font size. Here’s the jQuery:

jQuery('h1, h2, h3, h4').each(function() {
    var words = jQuery(this).text().split(' ');
    var i = 0;
    var hyphenate = false;
    while (i < words.length) {
        if (words[i].length >= 15) { hyphenate = true; break; }
        i++;
    }
    if (hyphenate) {
        jQuery(this).addClass('hyphenate-on-mobile');
    }
});

And then you just want to make sure that jQuery gets fired off when the page loads. It works!

Stupid jQuery and CSS tricks: Move a hidden element to the end of the parent

I just came up with a solution so simple, yet so stupid, that I had to share it.

The scenario is this: my client has some third-party JavaScript to inject a form into a page. I’ve been writing some of my own CSS to style the forms, including some crafty use of :nth-of-type(2n) and :nth-of-type(2n-1) to apply styles conditionally to adjacent fields in a two-up layout. (These are just sequential <div> tags, and I have to work with what I’ve got.) Specifically, I’m adding some right margin on the “left” element, and no right margin on the “right” element.

I noticed an instance where my margins were flipped for two fields, and when inspecting the code, I discovered why: the client has set up their form with a hidden field tucked in there before the “left” element. That’s throwing off the value for 2n in my CSS. I was going to contact them and ask them to update their form to put the hidden element at the end, but I realized this is a problem that is likely to recur, so I should just write in a workaround. (Yeah, yeah. But it’s the lesser of two evils.)

Fortunately, the site is already using jQuery, so a fix was super simple. I’m leaving the CSS class names here as they are in the actual site, but you may need to change them to suit your particular form.

jQuery('.form_container .form_page .form_question.hidden').each(function() {
    jQuery(this).appendTo(jQuery(this).parent());
});

Since the hidden field has the .hidden CSS class, it’s really easy to use the jQuery .appendTo() method to just take all of the hidden fields and shove them to the end of the container element. I used the parent and ancestor CSS classes in my jQuery selector just to be sure I’m isolating this action to these particular forms. Then of course I have to tell the page when to execute this functionality, which is ideally on the load event:

jQuery(window).on('load', function() { /* Code goes here */ });

It works!

Web developers: learn how to Google. If no one else has the same problem, the problem is you.

OK, maybe not you per se. This is not a judgment of your merits as a developer, or as a human being. But it does mean the problem is almost certainly something specific to the code you’ve written.

The Hierarchy of Coding Errors

If your code isn’t working, the source of the problem is one of the following, in order from most likely to least likely:

  1. New procedural code you’ve just written
  2. New object-oriented code you’ve just written*
  3. Custom functions or objects you built, but have used before
  4. Third-party/open source add-ons to the software platform you’re using (e.g. WordPress plugins)
  5. Standard functions or objects in the software platform (e.g. WordPress core)
  6. Public code libraries that are included in your chosen software platform (e.g. jQuery)
  7. Browser bugs
  8. OS bugs
  9. Internet protocol bugs
  10. Quantum fluctuations in the fabric of spacetime
  11. Gremlins

You may have guessed correctly at this point that this blog post is not just idle Friday afternoon musings. I’ve spent the majority of the day today troubleshooting a very strange issue with a website I’m currently building. I fixed the problem, but not after being forced to — once again — confront this humbling reality. If something’s not working, it’s probably your own fault. Especially if you’re the only person with the problem.

Googling the issue got me (almost) nowhere… which was the most obvious clue that it was my own fault

Aside from the natural human inclination to deflect blame, the tools we have for troubleshooting these types of problems are not necessarily well suited to forcing us to be honest with ourselves. It’s too easy to blame external forces.

Here’s my scenario. I found out last week while presenting work-in-progress to a client at their office that there was a JavaScript-related problem with the website. It only affected Internet Explorer (and Edge), which I had not yet tested the site in, and, weirdest of all, it didn’t always happen. I’d say maybe 10-20% of the time, the page loaded normally. But the rest of the time, it got an error.

Since this was only affecting one browser, my natural inclination was to start all the way at number 7 on the list, blaming Internet Explorer. But I’ve learned that as much as I want to blame it, issues with IE usually just shine a light on something in my own code that other browsers are more forgiving about. So it was time to walk backwards down the list. (Again… not really, but this is how it played out.)

The error that the browser reported was a “security problem” with jQuery Migrate. First I had to figure out what the hell jQuery Migrate was and why it was being loaded. (Turns out, it’s a place the jQuery team dumped deprecated code it pulled from version 1.9. It’s loaded by default by WordPress.)

With that in mind, this should be affecting every site I’ve built recently, since they’re all in WordPress. But it was only affecting this one site. So I had to try to narrow down where the problem exists. With WordPress, there are two main “variables” in the implementation: themes and plugins. When in doubt, try switching your theme and disabling the plugins you’re using. I started by disabling all of the plugins, one by one. No change. I found the error didn’t occur if I disabled Advanced Custom Fields, but that’s because half of the page didn’t load without it! (That’s another error on my part but let’s ignore that for now, shall we?)

OK, so it’s not a plugin. Next I swapped in the standard Twenty Sixteen theme in place of my custom theme. Not surprisingly, the error didn’t occur, but that didn’t help much because none of my Advanced Custom Fields content was in the pages. I still couldn’t rule out ACF as the culprit. But I tend to reuse field groups from site to site, so once again, if this were attributable to an ACF issue — even something specific to my field groups — it would’ve cropped up on another site.

So now I had little left to do but selectively comment out elements of the theme so I could narrow down where the problem was. (I make this all sound like a logical progression; in fact my debugging process is a lot more chaotic than this description — I actually did this commenting-out process haphazardly and repetitively throughout the afternoon.)

Eventually I pinpointed the troublesome block of code. Yes, it was #1 from the list. But as is usually the case with hard-to-diagnose problems, the complete picture here is that #1 included a combination of #3 and #5, which triggered an error message generated by #6, but only in the context of #7.

Yes. That’s what happened.

In the footer of the page, I had a link to the client’s email address. As is my standard (but by now probably outmoded) practice, I have a custom-built function I wrote years ago to obfuscate the email address by randomly converting most (but not all) of the characters in the string into HTML ampersand entities. My problem was not that function itself, which is tried and true. It’s that in this particular instance I called it on a string that included the mailto: pseudo-protocol, not just the email address itself.

I think the colon in mailto: is particularly significant to the problem, as evidenced by the fact that around 10-20% of the time the problem didn’t occur, and the page loaded normally. Since my obfuscation function randomly leaves characters in the string alone, that’s about how often the colon would have been kept untouched.

But even then, what difference should it make? Browsers decode those entity strings and can handle them in the href attribute of links just fine. However in this particular case I didn’t just use my obfuscation function. Without giving it much thought, in this particular site I had decided to wrap the obfuscated string in the standard WordPress esc_url() function. Trying to properly sanitize things, like a good developer. Right? Except — and I took a quick look at the source code to confirm it — there’s special handling in esc_url() for strings that don’t contain a colon. So the roughly 86% of the time that my string didn’t contain a colon, esc_url() was prepending http:// onto the string.

This situation was causing a particular piece of code in jQuery Migrate to barf… but only in Internet Explorer and Edge, for reasons I still don’t understand, but it has to do with how the different browsers handle security warnings in JavaScript. I found along the way (but before I had pinpointed the real problem) that if I commented out a particular segment of code in jQuery Migrate pertaining to the handling of selectors containing hashtags (see, the HTML ampersand entities again) I could get the page to load normally.

So, like I said, my newly written procedural code (#1), which itself included calls to both an existing custom function I wrote (#3) and a function baked into the WordPress core (#5), caused jQuery Migrate to issue an error (#6) but it was one that only a particular browser (Internet Explorer/Edge) cared to acknowledge (#7).

No wonder it took all afternoon to figure it out.

* The only reason I break out OO from procedural code is that OO has more structured patterns that are less likely to result in sloppy mistakes. Slightly.

Putting my money where my mouth is. OK, not money, but code. And not mouth, but… typed words.

On my Tools page, I tout my use of jQuery, which is true (I do use it), but up to now I wasn’t actually using it on my own site. Like the unkempt barber, I was always too busy cutting everyone else’s hair and not my own. And by hair I mean websites. And by cutting I mean building. So, sort of the opposite of cutting. But (as usual) I digress.

Before, the Web 2.0-ish, AJAX-ified, buzzword*-izationalized features of my site were kind of a hodgepodge of built-in WordPress features, homebrewed JavaScript and partially-implemented and or modified plug-ins.

Now I’m trying to streamline and consolidate it all on jQuery and, when applicable, jQuery-based WordPress plugins, dropping the last vestiges of Scriptaculous and prototype.js (oh how they’ve served me well). To that end, I’ve changed my navigation menus from my own quick-and-dirty style to something jQuery-based and unnecessarily showy. (I may drop the sliding animation once it starts to annoy me, which will be in about 14 minutes.)

I’ve also finally addressed my annoyance with the less-than-amazing new gallery feature in WordPress 2.5. Granted, it’s way better than what I was using before, but I really don’t like how clicking a thumbnail loads another blog page that just contains the larger version of the photo, with the photo’s filename as the title. Yuck. But I found a nice jQuery-based lightbox plug-in that does exactly what I wanted. Now anywhere on my site where I’ve got a link directly to an image, that image loads in a lightbox layer instead of redirecting to another page or just a blank window. (And I didn’t even have to add a bunch of rel="lightbox" attributes to my old code like before! [And even better, I didn’t have to take out the ones I had already added!!!!])

So… well, you are either a web designer/developer, in which case you are ever-so-slightly interested, or you’re not, and you’re not. But I am, and I am, and I am very pleased with the results so far!

And the last thing I have to say is, given my inclination to talk in circles tonight solely to amuse myself, it’s probably a good idea that I decided to spend the evening tinkering with my own site rather than working on a client’s project!

* I just love how the page I linked to notes that “This page may not work with Microsoft Internet Explorer 3.xx.” Only on a page whose URL contains both .edu and a tilde. I just installed Multiple IE in my new copy of Windows last night, so maybe I should fire up IE 3.1 and see if he’s right.