A single-serving website from Alexander Vishnyakov for testing if it’s valid to put any particular HTML element within another type of HTML element. Kinda neat to have a quick reference for this.
Some combinations feel fairly obvious: can you put a <video> inside an <input>? Uh, no. Some are trickier: can you put a <div> inside an <h1>? Nope — that one bit me this week (derp). Some are a little confusing, like <div> is an invalid child of an <ol> but a valid child of a <dl>.
Remember Tyler Hall’s personal story of a UX moment where the popup sharing context menu on iOS had no visible indication that the content inside was scrollable? The thing his mom wanted to do seemed impossible iOS isn’t alone here — Terence Eden documents essentially the same problem on Android:
I tried sharing a website using Google Chrome for Android. I hit the share button, and a panel popped-up from the bottom of the screen.
Hmmm. It didn’t have the share destination that I wanted. It was early in the morning – when I’m not at my cognitive best – and I was stumped. There is nothing on this screen – other than the icons – to tell me how I can interact with it. There’s no scrollbar, no handle, no “more” icon, nothing.
I would think even just fairly subtle “scroll shadows” would go a long way in both cases, but some serious user testing should be in order here.
A friend once contacted me asking if I had a way to dynamically change one HTML element into another within Vue’s template block. For instance, shifting a <div> element to a <span> element based on some criteria. The trick was to do this without relying on a series of v-if and v-else code.
I didn’t think much of it because I couldn’t see a strong reason to do such a thing; it just doesn’t come up that often. Later that same day, though, he reached out again and told me he learned how to change element types. He excitedly pointed out that Vue has a built-in component that can be used as a dynamic element in the very way that he needed.
This small feature can keep code in the template nice and tidy. It can reduce v-if and v-else glut down to a smaller amount of code that’s easier to understand and maintain. This allows us to use methods or computed methods to create nicely-coded, and yet more elaborate, conditions in the script block. That’s where such things belong: in the script, not the template block.
I had the idea for this article mainly because we use this feature in several places in the design system where I work. Granted it’s not a huge feature and it is barely mentioned in the documentation, at least as far as I can tell. Yet it has potential to help render specific HTML elements in components.
Vue’s built-in <component> element
There are several features available in Vue that allow for easy dynamic changes to the view. One such feature, the built-in <component> element, allows components to be dynamic and switched on demand. In both the Vue 2 and the Vue 3 documentation, there is a small note about using this element with HTML elements; that is the part we shall now explore.
The idea is to leverage this aspect of the <component> element to swap out common HTML elements that are somewhat similar in nature; yet with different functionality, semantics, or visuals. The following basic examples will show the potential of this element to help with keeping Vue components neat and tidy.
Button or link?
Buttons and links are often used interchangeably, but there are big differences in their functionality, semantics, and even visuals. Generally speaking, a button (<button>) is intended for an internal action in the current view tied to JavaScript code. A link (<a>), on the other hand, is intended to point to another resource, either on the host server or an external resource; most often web pages. Single page applications tend to rely more on the button than the link, but there is a need for both.
Links are often styled as buttons visually, much like Bootstrap’s .btn class that creates a button-like appearance. With that in mind, we can easily create a component that switches between the two elements based on a single prop. The component will be a button by default, but if an href prop is applied, it will render as a link.
This bound is attribute points to a computed method named element and the bound href attribute uses the aptly named href prop. This takes advantage of Vue’s normal behavior that the bound attribute does not appear in the rendered HTML element if the prop has no value. The slot provides the inner content regardless whether the final element is a button or a link.
The computed method is simple in nature:
element () { return this.href ? 'a' : 'button'; }
If there’s an href prop,. then an <a> element is applied; otherwise we get a <button>.
<my-button>this is a button</my-button> <my-button href="https://www.css-tricks.com">this is a link</my-button>
The HTML renders as so:
<button class="my-button">this is a button</button> <a href="https://www.css-tricks.com" class="my-button">this is a link</a>
In this case, there could be an expectation that these two are similar visually, but for semantic and accessibility needs, they are clearly different. That said, there’s no reason the two outputted elements have to be styled the same. You could either use the element with the selector div.my-button in the style block, or create a dynamic class that will change based on the element.
The overall goal is to simplify things by allowing one component to potentially render as two different HTML elements as needed — without v-if or v-else!
Ordered or unordered list?
A similar idea as the button example above, we can have a component that outputs different list elements. Since an unordered list and an ordered list make use of the same list item (<li>) elements as children, then that’s easy enough; we just swap <ul> and <ol>. Even if we wanted to have an option to have a description list, <dl>, this is easily accomplished since the content is just a slot that can accept <li> elements or <dt>/<dd>combinations.
The template code is much the same as the button example:
<component :is="element" class="my-list" > <slot>No list items!</slot> </component>
Note the default content inside the slot element, I’ll get to that in a moment.
There is a prop for the type of list to be used that defaults to <ul>:
element () { if (this.$ slots.default) { return this.listType; } else { return 'div'; } }
In this case, we are testing if the default slot exists, meaning it has content to render. If it does, then the the list type passed through the listType prop is used. Otherwise, the element becomes a <div> which would show the “No list items!” message inside the slot element. This way, if there are no list items, then the HTML won’t render as a list with one item that says there are no items. That last aspect is up to you, though it is nice to consider the semantics of a list with no apparent valid items. Another thing to consider is the potential confusion of accessibility tools suggesting this is a list with one item that just states there are no items.
Just like the button example above, you could also style each list differently. This could be based on selectors that target the element with the class name, ul.my-list. Another option is to dynamically change the class name based on the chosen element.
This example follows a BEM-like class naming structure:
<component :is="element" class="my-list" :class="`my-list__$ {element}`" > <slot>No list items!</slot> </component>
Usage is as simple as the previous button example:
Each instance renders the specified list element. The last one, though, results in a <div> stating no list items because, well, there’s no list to show!
One might wonder why create a component that switches between the different list types when it could just be simple HTML. While there could be benefits to keeping lists contained to a component for styling reasons and maintainability, other reasons could be considered. Take, for instance, if some forms of functionality were being tied to the different list types? Maybe consider a sorting of a <ul> list that switches to a <ol> to show sorting order and then switching back when done?
Now we’re controlling the elements
Even though these two examples are essentially changing the root element component, consider deeper into a component. For instance, a title that might need to change from an <h2> to an <h3> based on some criteria.
If you find yourself having to use ternary solutions to control things beyond a few attributes, I would suggest sticking with the v-if. Having to write more code to handle attributes, classes, and properties just complicates the code more than the v-if. In those cases, the v-if makes for simpler code in the long run and simpler code is easier to read and maintain.
When creating a component and there’s a simple v-if to switch between elements, consider this small aspect of a major Vue feature.
Expanding the idea, a flexible card system
Consider all that we’ve covered so far and put it to use in a flexible card component. This example of a card component allows for three different types of cards to be placed in specific parts of the layout of an article:
Hero card: This is expected to be used at the top of the page and draw more attention than other cards.
Call to action card: This is used as a line of user actions before or within the article.
Info card: This is intended for pull quotes.
Consider each of these as following a design system and the component controls the HTML for semantics and styling.
In the example above, you can see the hero card at the top, a line of call-to-action cards next, and then — scrolling down a bit — you’ll see the info card off to the right side.
There are three of the “component” elements in the card. Each represents a specific element inside the card, but will be changed based on what kind of card it is. Each component calls the elements() method with a parameter identifying which section of the card is making the call.
There are probably several ways of handing this, but you’ll have to go in the direction that works with your component’s requirements. In this case, there is an object that keeps track of HTML element tags for each section in each card type. Then the method returns the needed HTML element based on the current card type and the parameter passed in.
For the styles, I inserted a class on the root element of the card based on the type of card it is. That makes it easy enough to create the CSS for each type of card based on the requirements. You could also create the CSS based on the HTML elements themselves, but I tend to prefer classes. Future changes to the card component could change the HTML structure and less likely to make changes to the logic creating the class.
The card also supports a background image on the header for the hero card. This is done with a simple computed placed on the header element: bg. This is the computed:
If an image URL is provided in the background prop, then the computed returns a string for an inline style that applies the image as a background image. A rather simple solution that could easily be made more robust. For instance, it could have support for custom colors, gradients, or default colors in case of no image provided. There’s a large number of possibilities that his example doesn’t approach because each card type could potentially have their own optional props for developers to leverage.
You’ll see that each section of the card has its own slot for content. And, to keep things simple, text is the only thing expected in the slots. The card component handles the needed HTML element based solely on the card type. Having the component just expect text makes using the component rather simplistic in nature. It replaces the need for decisions over HTML structure to be made and in turn the card is simply implemented.
For comparison, here are the other two types being used in the demo:
<custom-card type="cta"> <template v-slot:header>CTA Title One</template> <template v-slot:content>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</template> <template v-slot:footer>footer</template> </custom-card> <custom-card type="info"> <template v-slot:header>Here's a Quote</template> <template v-slot:content>“Maecenas ... quis.”</template> <template v-slot:footer>who said it</template> </custom-card>
Again, notice that each slot only expects text as each card type generates its own HTML elements as defined by the elements() method. If it’s deemed in the future that a different HTML element should be used, it’s a simple matter of updating the component. Building in features for accessibility is another potential future update. Even interaction features can be expanded, based on card types.
The power is in the component that’s in the component
The oddly named <component> element in Vue components was intended for one thing but, as often happens, it has a small side effect that makes it rather useful in other ways. The <component> element was intended to dynamically switch Vue components inside another component on demand. A basic idea of this could be a tab system to switch between components acting as pages; which is actually demonstrated in the Vue documentation. Yet it supports doing the same thing with HTML elements.
This is an example of a new technique shared by a friend that has become s surprisingly useful tool in the belt of Vue features that I’ve used. I hope that this article carries forward the ideas and information about this small feature for you to explore how you might leverage this in your own Vue projects.
I’d say 85% of my grid usage is in one of these two categories…
I just need some pretty basic (probably equal width) columns that ends up being something like like grid-template-columns: repeat(3, minmax(0, 1fr));to be safe.
Actually doing some real layout where five minutes in I realize I’d really like subgrid.
Subgrid? It’s a nice intuitive way to have a child element on the grid inherit relevant grid lines from the parent grid.
Here’s a great recent video from Rachel Andrew covering it. Last year, we linked up her talk on the same! It’s such a clutch feature and I wish we could rely on it cross-browser. Right now, Firefox is the only one that has it. (Chrome issue, Safari issue)
In my recent video, right about at 20 minutes, I realize subgrid would make even a fairly simple layout much nicer, like removing the need for variables or resorting to magic numbers.
In this post, we’re going to use CSS superpowers to create a visual effect where two elements overlap and weave together. The epiphany for this design came during a short burst of spiritual inquisitiveness where I ended up at The Bible Project’s website. They make really cool animations, and I mean, really cool animations.
My attention, however, deviated from spiritualism to web design as I kept spotting these in-and-out border illustrations.
Screenshot form The Bible Project website.
I wondered if a similar could be made from pure CSS… and hallelujah, it’s possible!
The red frame is created using border. Its box-sizing is set to include the border size in the dimensions of the box so that the frame is centered around the picture after being rotated. Otherwise, the frame will be bigger than the image and get pulled towards the bottom-right corner.
Then we pick a pair of opposite corners of the image and overlay their quadrants with their corresponding portion in a copy of the same image as before. This hides the red frame in those corners.
We basically need to make a cut portion of the image that looks like below to go on top of the red frame.
The visible two quadrants will lay on top of the .rotated-border element.
So, how do we alter the image so that only two quadrants of the image are visible? CSS Blend Modes! The multiply value is what we’re going to reach for in this instance. This adds transparency to an element by stripping white from the image to reveal what’s behind the element.
Chris has a nice demo showing how a red background shows through an image with the multiply blend mode.
OK, nice, but what about those quadrants? We cover the quadrants we want to hide with white grid cells that will cause the image to bleed all the way through in those specific areas with a copy of the bird image right on top of it in the sourcecode.
<div id="design"> <img src="bird-photo.jpg"> <div class="rotated-border"></div> <div class="blend"> <!-- Copy of the same image --> <img src="bird-photo.jpg"> <div class="grid"> <!-- Quadrant 1: Top Left --> <div></div> <!-- Quadrant 2: Top Right --> <div data-white></div> <!-- Quadrant 3: Bottom Left --> <div data-white></div> <!-- Quadrant 4: Bottom Right --> <div></div> </div> </div> </div>
.blend > * { position: absolute; height: 100%; width: 100%; } /* Establishes our grid */ .grid { display: grid; grid: repeat(2, 1fr) / repeat(2, 1fr); } /* Adds white to quadrants with this attribute */ [data-white]{ background-color: white; }
The result is a two-by-two grid with its top-right and bottom-left quadrants that are filled with white, while being grouped together with the image inside .blend.
To those of you new to CSS Grid, what we’re doing is adding a new .grid element that becomes a “grid” element when we declare display: grid;. Then we use the grid property (which is a shorthand that combinesgrid-template-columns and grid-template-rows) to create two equally spaced rows and columns. We’re basically saying, “Hey, grid, repeat two equal columns and repeat two equal rows inside of yourself to form four boxes.”
A copy of the image and a grid with white cells on top of the red border.
Now we apply the multiply blend mode to .blend using the mix-blend-mode property.
.blend { mix-blend-mode: multiply; }
The result:
As you can see, the blend mode affects all four quadrants rather than just the two we want to see through. That means we can see through all four quadrants, which reveals all of the red rotated box.
We want to bring back the white we lost in top-left and bottom-right quadrants so that they hide the red rotated box behind them. Let’s add a second grid, this time on top of .blend in the sourcecode.
<div id="design"> <img src="bird-photo.jpg"> <div class="rotated-border"></div> <!-- A second grid --> <!-- This time, we're adding white to the image quandrants where we want to hide the red frame --> <div class="grid"> <!-- Quadrant 1: Top Left --> <div data-white></div> <!-- Quadrant 2: Top Right --> <div></div> <!-- Quadrant 3: Bottom Left --> <div></div> <!-- Quadrant 4: Bottom Right --> <div data-white></div> </div> <div class="blend"> <img src="bird-photo.jpg"> <div class="grid"> <!-- Quadrant 1: Top Left --> <div></div> <!-- Quadrant 2: Top Right --> <div data-white></div> <!-- Quadrant 3: Bottom Left --> <div data-white></div> <!-- Quadrant 4: Bottom Right --> <div></div> </div> </div> </div>
The result!
Summing up, the browser renders the elements in our demo like this:
At bottommost is the bird image (represented by the leftmost grey shape in the diagram below)
Then a rotated red frame
On top of them is a grid with top-left and bottom-right white cells (corners where we don’t want to see the red frame in the final result)
Followed by a copy of the bird image from before and a grid with top-right and bottom-left white cells (corners where we do want to see the red frame) – both grouped together and given the blending mode, multiply.
You may have some questions about the approach I used in this post. Let me try to tackle those.
What about using CSS Masking instead of CSS Blend Modes?
For those of you familiar with CSS Masking – using either mask-image or clip-path – it can be an alternative to using blend mode.
I prefer blending because it has better browser support than masks and clipping. For instance, WebKit browsers don’t support SVG <mask> reference in the CSS mask-image property and they also provide partial support for clip-path values, especially Safari.
Another reason for choosing blend mode is the convenience of being able to use grid to create a simple white structure instead of needing to create images (whether they are SVG or otherwise).
Then again, I’m fully on board the CSS blend mode train, having used it for knockout text, text fragmentation effect… and now this. I’m pretty much all in on it.
Why did you use grid for the quadrants?
The white boxes needed in the demo can be created by other means, of course, but grid makes things easier for me. For example, we could’ve leaned on flexbox instead. Use what works for you.
Why use a data-attribute on the grid quadrant elements to make them white?
I used it while coding the demo without thinking much about it – I guess it was quicker to type. I later thought of changing it to a class, but left it as it is because the HTML looked neater that way… at least to me. 🙂
Is multiply the only blend mode that works for this example?
Nope. If you already know about blend modes then you probably also know you can use either screen, darken, or lighten to get a similar effect. (Both screen and lighten will need black grid cells instead of white.)
On March 6, 2018, a new bug was added to the official Mozilla Firefox browser bug tracker. A developer had noticed an issue with Mozilla’s nightly build. The report noted that a 14-day weather forecast widget typically featured on a German website had all of a sudden broken and disappeared. Nothing on the site had changed, so the problem had to be with Firefox.
A screenshot of the bug report filed with Mozilla.
The problem, the developer noted in his report, appeared to stem from the site’s use of the JavaScript library MooTools.
At first glance, the bug appeared to be fairly routine, most likely a small problem somewhere in the website’s code or a strange coincidence. After just a few hours though, it became clear that the stakes for this one particular bug were far graver than anyone could have anticipated. If Firefox were to release this version of their browser as-is, they risked breaking an unknown, but still predictably rather large number of websites, all at once. Why that is has everything to do with the way MooTools was built, where it drew influence from, and the moment in time it was released. So to really understand the problem, we’ll have to go all the way back to the beginning.
In the beginning
First came plain JavaScript. Released in 1995 by a team at Netscape, Javascript began making its way into common use in the late 90’s. JavaScript gave web developers working with HTML a boost, allowing them to dynamically shift things around, lightly animate content, and add counters and stock tickers and weather widgets and all sorts of interactivity to sites.
By 2005, JavaScript development had become increasingly complex. This was precipitated by the use of a technique we know as Asynchronous JavaScript and XML (Ajax), a pattern that likely feels familiar these days for anyone that uses a website to do something more than just read some content. Ajax opened up the door for application-like functionality native to the web, enabling the release of projects like Google Maps and Gmail. The phrase “Web 2.0” was casually lobbed into conversation to describe this new era of dynamic, user-facing, and interactive web development. All thanks to JavaScript.
It was specifically Ajax that Sam Stephenson found himself coming back to again and again in the early years of the turn of the century. Stephenson was a regular contributor to Ruby on Rails, and kept running into the same issues when trying to connect to Rails with JavaScript using some fairly common Ajax code. Specifically, he was writing the same baseline code every time he started a new project. So he wrote a few hundred lines of code that smoothed out Ajax connections with Rails he could port to all of his projects. In just a few months, a hundred lines turned into many more and Prototype, one of the earliest examples of a full JavaScript framework, was officially released.
An early version of the Prototype website that emphasizes its ease of use and class-based structure.
Extending JavaScript
Ruby utilizes class inheritance, which tends to lend itself to object-oriented development. If you don’t know what that means, all you really need to know is that it runs a bit counter to the way JavaScript was built. JavaScript instead leans on what’s known as prototypal inheritance. What’s that mean? It means that everything in JavaScript can be extended using the base object as a prototype. Anything. Even native object prototypes like String or Array. In fact, when browsers do add new functions and features to Javascript, they often do so by taking advantage of this particular language feature. That’s where Stephenson got the name for his library, Prototype.
The bottom line is, prototypal inheritance makes JavaScript naturally forgiving and easily extendable. Its basically possible for any developer to build on top of the core JavaScript library in their own code. This isn’t possible in a lot of other programming languages, but JavaScript has always been a bit of an outlier in terms of its approach to accommodate a much larger, cross-domain developer base.
All of which is to say that Stephenson did two things when he wrote Prototype. The first was to add a few helpers that allowed object-oriented developers like himself to work with JavasScript using a familiar code structure. The second, and far more important here, is that he began to extend existing Javascript to add features that were planned for some point in the future but not implemented just yet. One good example of this was the function document.getElementByClassName, a slightly renamed version of a feature that wouldn’t actually land in JavaScript until around 2008. Prototype let you use it way back in 2006. The library was basically a wish list of features that developers were promised would be implemented by browsers sometime in the future. Prototype gave those developers a head-start, and made it much easier to do the simple things they had to do each and every day.
Prototype went through a few iterations in rapid succession, gaining significant steam after it was included by default in all Ruby on Rails installations not long after its release. Along the way, Prototype set the groundwork for basically every framework that would come after it. For instance, it was the first to use the dollar sign ($ ) as shorthand for selecting objects in JavaScript. It wrote code that was, in its own words, “self-documented,” meaning that documentation was scarce and learning the library meant diving into some code, a practice that is more or less commonplace these days. And perhaps most importantly, it removed the difficulty of making code run on all browsers, a near Herculean task in the days when browsers themselves could agree on very little. Prototype just worked, in every modern-at-the-time browser.
Prototype had its fair share of competition from other libraries like base2 which took the object-oriented bits of Prototype and spun them off into a more compact version. But the library’s biggest competitor came when John Resig decided to put his own horse in the race. Resig was particularly interested in that last bit, the work-in-all-browsers-with-the-same-code bit. He began working on a different take on that idea in 2005, and eventually unveiled a library of his own at Barcamp in New York in January of 2006.
It was called jQuery.
New Wave JavaScript
jQuery shipped with the tagline “New Wave Javascript,” a curious title given how much Resig borrowed from Prototype. Everything from the syntax to its tools for working with Ajax — even its use of a dollar sign as a selector — came over from Prototype to jQuery. But it wasn’t called New Wave JavaScript because it was original. It was called New Wave JavaScript because it was new.
“New Wave” Javascript
jQuery’s biggest departure from Prototype and its ilk was that it didn’t extend existing and future JavaScript functionality or object primitives. Instead, it created brand new features, all assembled with a unique API that was built on top of what already existed in JavaScript. Like Prototype, jQuery provided lots of ways to interact with webpages, like select and move around elements, connect to servers, and make pages feel snappy and dynamic (though it lacked the object-oriented leanings of its predecessor). Crucially, however, all of this was done with new code. New functions, new syntax, new API’s, hence a new wave of development. You had to learn the “jQuery way” of doing things, but once you did, you could save yourself tons of time with all of the stuff jQuery made a lot easier. It even allowed for extendable plugins, meaning other developers could build cool, new stuff on top of it.
MooTools
It might sound small, but that slight paradigm shift was truly massive. A shift that seismic required a response, a response that incidentally came the very next year, in 2007, when Valerio Proietti found himself entirely frustrated with another library altogether. The library was called script.aculo.us, and it helped developers with page transitions and animations. Try as he might, Proietti just couldn’t get script.aculo.us to do what he wanted to do, so (as many developers in his position have done in the past), he decided to rewrite his own version. An object-oriented developer himself, he was already a big fan of Protoype, so he based his first version off of the library’s foundational principles. He even attempted to coast off its success with his first stab at a name: prototype.lite.js. A few months and many new features later, Proietti transformed that into MooTools.
Like Protoype, MooTools used an object-oriented programming methodology and prototypical inheritance to extend the functionality of core JavaScript. In fact, most of MooTools was simply about adding new functionality to built-in prototypes (i.e. String, Array). Most of what MooTools added was on the JavaScript roadmap for inclusion in browsers at some point in the future; the library was there to fill in the gap in the meantime. The general idea was that once a feature finally did land in browsers, they’d simply update their own code to match it. Web designers and developers liked MooTools because it was powerful, easy to use, and made them feel like they were coding in the future.
MooTools: Object-oriented, developer-friendly
There was plenty there from jQuery too. Like jQuery, MooTools smoothed over inconsistencies and bugs in the various browsers on the market, and offered quick and easy ways to add transitions, make server requests, and manipulate webpages dynamically. By the time MooTools was released, the jQuery syntax had more or less become the standard, and MooTools was not going to be the one to break the mold.
There was enough similarities between the two, in fact, for them to be pitted against one another in a near-endless stream of blog posts and think-pieces. MooTools vs. jQuery, a question for the ages. Websites sprung up to compare the two. MooTools was a “framework,” jQuery was a “library.” MooTools made coding fun, jQuery made the web fun. MooTools was for Geminis, and jQuery was for Sagittariuses. In truth, both worked very well, and the use of one over the other was mostly a matter of personal preference. This is largely true of many of the most common developer library debates, but they continue on all the same.
The legacy of legacy frameworks
Ultimately, it wasn’t features or code structure that won the day — it was time. One by one, the core contributors of MooTools peeled off from the project to work on other things. By 2010, only a few remained. Development slowed, and the community wasn’t far behind. MooTools continued to be popular, but its momentum had come to a screeching halt.
jQuery’s advantage was simply that they continued on, expanded even. In 2010, when MooTools development began to wind down, jQuery released the first version of jQuery Mobile, an attempt at retooling the library for a mobile world. The jQuery community never quit, and in the end, it gave them the advantage.
The legacy and reach of MooTools, however, is massive. It made its way onto hundreds of thousands of sites, and spread all around the world. According to some stats we have, it is still, to this day, more common to see MooTools than Angular or React or Vue or any modern framework on the average website. The code of some sites were updated to keep pace with the far less frequent, but still occasional, updates to MooTools. Others to this day are comfortable with whatever version of MooTools they have installed. Most simply haven’t updated their site at all. When the site was built, MooTools was the best option available and now, years later, the same version remains.
Array.flatten
Which brings us all the way back to the bug in the weather app that popped up in Firefox in early 2018. Remember, MooTools was modeled after Prototype. It modified native JavaScript prototype objects to add some functions planned but not yet released. In this specific case, it was a method called Array.flatten, a function that MooTools first added to their library way back in 2008 for modifying arrays. Fast forward 10 years, and the JavaScript working group finally got around to implementing their own version of Array.flatten, starting with the beta release of Firefox.
The problem was that Firefox’s Array.flatten didn’t map directly to the MooTools version of Array.flatten.
The details aren’t all that important (though you can read more about it here). Far more critical was the uncomfortable implication. The MooTools version, as it stood, broke when it collided with the new JavaScript version. That’s what broke the weather widget. If Firefox were to release their browser to the larger public, then the MooTools version of flatten would throw an error, and wipe out any JavaScript that depended on it. No one could say how many sites might be affected by the conflict, but given the popularity of MooTools, it wasn’t at all out of the question to think that the damage could be extensive.
Once the bug surfaced, hurried discussion took place in the JavaScript community, much of it in the JavaScript working group’s public GitHub repo. A few solutions soon emerged. The first was to simply release the new version of flatten. Essentially, to let the old sites break. There was, it was argued, a simple elegance to the proposal, backed fundamentally by the idea that it is the responsibility of browsers to push the web forward. Breaking sites would force site owners to upgrade, and we could finally rid ourselves of the old and outdated MooTools versions.
Others quickly jumped in to point out that the web is near limitless and that it is impossible to track which sites may be affected. A good amount of those sites probably hadn’t been updated in years. Some may have been abandoned. Others might not have the resources to upgrade. Should we leave these sites to rot? The safe, forgivable approach would be to retool the function to be either backward or fully compatible with MooTools. Upon release, nothing would break, even if the final implementation of Array.flatten was less than ideal.
Somewhere down the middle, a final proposition suggested the best course of action may simply be to rename the function entirely, essentially sidestepping the issue altogether and avoiding the need for the two implementations to play nice at all.
One developer suggested that the name Array.smoosh be used instead, which eventually lead to the whole incident to be labeled Smooshgate, which was unfortunate because it glossed over a much more interesting debate lurking just under the surface about the very soul of the web. It exposed an essential question about the responsibility of browser makers and developers to provide an accessible and open and forgiving experience for each and every user of the web and each and every builder of the web, even when (maybe especially when) the standards of the web are completely ignored. Put simply, the question was, should we ever break the web?
To be clear, the web is a ubiquitous and rapidly developing medium originally built for sharing text and links and little else, but now used by billions of people each day in every facet of their lives to do truly extraordinary things. It will, on occasion, break all on its own. But, when a situation arises that is in full view and, ultimately, preventable, is the proper course of action to try and pull the web forward or to ensure that the web in its current form continues to function even as technology advances?
This only leads to more questions. Who should be responsible for making these decisions? Should every library be actively maintained in some way, ad infinitum, even when best practices shift to anti-patterns? What is our obligation, as developers, for sites we know have been abandoned? And, most importantly, how can we best serve the many different users of the web while still giving developers new programmatic tools? These are the same questions that we continue to return to, and they have been at the core of discussions like progressive enhancement, responsive design and accessibility.
Where do we go now?
It is impossible to answer all of these questions simply. They can, however, be framed by the ideological project of the web itself. The web was built to be open, both technologically as a decentralized network, and philosophically as a democratizing medium. These questions are tricky because the web belongs to no one, yet was built for everyone. Maintaining that spirit takes a lot of work, and requires sometimes slow, but always deliberate decisions about the trajectory of web technologies. We should be careful to consider the mountains of legacy code and libraries that will likely remain on the web for its entire existence. Not just because they are often built with the best of intentions, but because many have been woven into the fabric of the web. If we pull on any one thread too hard, we risk unraveling the whole thing.
As the JavaScript working group progressed towards a fix, many of these questions bubbled up in one form or another. In the end, the solution was a compromise. Array.flatten was renamed to Array.flat, and is now active in most modern browser releases. It is hard to say if this was absolutely the best decision, and certainly we won’t always get things right. But if we remember the foundational ideals of the web — that it was built as an accessible, inclusive and always shifting medium, and use that as a guide — then it can help our decision-making process. The seems to have been at the core of the case with Smooshgate.
Someday, you may be browsing the web and come across an old site that hasn’t been updated in years. At the top, you may even notice a widget that tells you what the weather is. And it will keep on working because JavaScript decided to bend rather than break.
Enjoy learning about web history with stories just like this? Jay Hoffmann is telling the full story of the web, all the way from the beginning, over on The History of the Web. Sign up for his newsletter to catch up on the latest… of what’s past!