Logo

dev-resources.site

for different kinds of informations.

Webdev WTF

Published at
12/17/2020
Categories
webdev
css
html
w3c
Author
vfonic
Categories
4 categories in total
webdev
open
css
open
html
open
w3c
open
Author
6 person written this
vfonic
open
Webdev WTF

Have you ever hit a strange issue while doing frontend development and said WTF?

I thought it might be interesting to share these WTF moments and maybe learn something from each other and have a little laugh.

Here are some of the WTFs I've encountered in my 10+ years of frontend development.

document.querySelectorAll does not return an actual array

document.querySelectorAll does not return an actual array, but a NodeList instance that only partially acts like an array: typeof document.querySelectorAll('a').map === 'undefined'

NodeList has #forEach method, but doesn't have #map method. It's a mess. :)

Getting CSS styles of a DOM element in JS

There's el.style, but that only works for inline styles in HTML: <div style="...">. Then there's the global getComputedStyle(Element, pseudo) which almost works, but not quite (depending on what you need):

body > .container {
  background: none;
}
Enter fullscreen mode Exit fullscreen mode
getComputedStyle(containerEl).background
// => "rgba(0, 0, 0, 0) none repeat scroll 0% 0% / auto padding-box border-box"
Enter fullscreen mode Exit fullscreen mode

This happens because background is a shorthand property for many other properties (such as backgroundColor, etc.)
What if I want to get the exact CSS style from the CSS? I personally have no idea how to do that.

Super complicated to get URL params

window.location is not a string. It's not a URL either. It's...Location. Let's see how we could get the URL params.
An instance of URL class has: searchParams method. We can create a URL instance from Location:

// imagine window.location is https://example.com/events/new?premium=true#buy
const url = new URL(window.location)
const whyIsThisCalledSearchParams = url.searchParams
whyIsThisCalledSearchParams.toString() // => "premium=true"
Enter fullscreen mode Exit fullscreen mode

IT WORKS!!!! 😍

Not so fast, Mr. Gordon.

JSON.stringify(whyIsThisCalledSearchParams) // => "{}"
// WAT
Enter fullscreen mode Exit fullscreen mode

Ok, well, there's #entries() method. I guess that's like Object.entries(), right? Let's use that:

Object.entries({ name: 'Viktor' })
// => [["name", "Viktor"]]
whyIsThisCalledSearchParams.entries()
// => Iterator {}
// WAT it's empty
Object.entries(new URL(location).searchParams)
// => []
// WAT it's empty
Enter fullscreen mode Exit fullscreen mode
whyIsThisCalledSearchParams.get('premium')
// => "true"
// of course, true is a string here, but that's ok
Enter fullscreen mode Exit fullscreen mode

The only way to get the url query parameters:

for (const [key, value] of whyIsThisCalledSearchParams) {}
Enter fullscreen mode Exit fullscreen mode

Or you can do the old-fashioned way:

// because first character is "?" because why not :)
const query = window.location.search.substring(1)
query.split('&').....each(queryPair => queryPair.split('='))
Enter fullscreen mode Exit fullscreen mode

And then you hope you won't need arrays in there...I also forgot to mention parsing any special characters...sorry! :)

Also, searchParams is called query in the official RFCs. To me, "query" or "query params" make more sense than "search params".

In JavaScript you can't get all form field values through standard API

formEl.formValues or similar doesn't exist. You have to do: formEl.querySelectorAll('input, select').map(el => el.value). But that won't work for several reasons. First, you can't use .map, but we'll get to that in a moment.
Second, you can have input fields outside of the formEl:

<input type="text" form="editform" name="id">

<form action="datamanager" id="editform"></form>
Enter fullscreen mode Exit fullscreen mode

This works.

So you need to do all this extra mumbo jumbo similar to this:

formEl.querySelectorAll('input, select').forEach(el => {
  if (el.type === 'checkbox' || el.type === 'radio') {
    el.checked
  } else {
    el.value
  }
}
if (formEl.id) {
  document.querySelectorAll('input[form="' + formEl.id + '"]').forEach(...)
}
Enter fullscreen mode Exit fullscreen mode

I lied. You can get the form values using the FormData class and its #entries() method. Maybe.
It might work, but it might fail silently (which is the worst possible way to fail, when you don't know it failed) if you decide to add an input element outside of the form tag programmatically:

const inputEl = document.createElement('input')
inputEl.name = 'firstName'
inputEl.form = 'customerForm'
inputEl.form
// => null
// WAT it just fails silently
inputEl.setAttribute('form', 'customerForm')
// => works as expected
Enter fullscreen mode Exit fullscreen mode

dataset vs data-* vs dataset.kebabCase vs data-kebab-case

In HTML you write: data-target-id="someid", while in JavaScript, to get that same attribute value, you say: el.dataset.targetId. WAT.

CSS usually (on a good day) prefers class names with kebab case, but JS prefers pascalCase:

.container {
  background-color: #ffffff;
`
Enter fullscreen mode Exit fullscreen mode
containerEl.style.backgroundColor = '#ffffff'
Enter fullscreen mode Exit fullscreen mode

Also check these great examples:

div {
  display: inline-block; /* kebab case, as the rest of the CSS */
  white-space: nowrap; /* nowrap? WAT no-wrap? WAT */
}
Enter fullscreen mode Exit fullscreen mode

How about this:

button {
  white-space: nowrap;
}
div {
  white-space: no-pre; /* What the... 🤯 */
}
Enter fullscreen mode Exit fullscreen mode

Getting element's X/Y position on the page from page top

This works:

el.getBoundingClientRect().top + window.pageYOffset
Enter fullscreen mode Exit fullscreen mode

Or does it?

Well, sort-of. It works if the element is not in a inside some container that's position fixed. So you first have to find check all of the element's ancestors to see if any one of those is position fixed and only then you can calculate this correctly. Please correct me if I'm wrong here. I'd love to be wrong here.

Does this look familiar: z-index: 9999999999999999?

You add z-index: 9999999999999999 to an element, but it's still not above all the other elements. Y U NO?
It's because z-index is "stacking". So it works kind of like this:

<div id="header" style="z-index: 2"></div>
<div id="main-content" style="z-index: 1">
  <div id="dis-one" style="z-index: 999"></div>
</div>
Enter fullscreen mode Exit fullscreen mode

The #dis-one element has an overall z-index of 1.999, while #header has an overall z-index of 2. It stacks.

Well, yeah...maybe. But not always.

First of all, you need to add at least position: relative for z-index to have any effect. Secondly, new stacking contexts are also created when you apply a transform. So, sometimes to show .container:before behind .container you need to actually add another HTML element (let's call it) .wrapper around .container.

Check out this answer:
https://stackoverflow.com/a/20852489/336806

<input type="submit"> and <button>

There's a special input type called "submit", which kind-of renders like a button. It also has a value attribute, but it's usually not submitted to the backend. Remember our code for getting form values? Well, it does submit this value. That's another edge case you need to take care of.
It's also far more limiting than an actual <button>

Speaking of <button>:

The <button>

Here's a part of a website's HTML:

<button>Submit</button>
Enter fullscreen mode Exit fullscreen mode

...but it's not working. 🤔 The form doesn't get submitted when you click on this button.

You know that button's default type is type="submit". And you see no JavaScript code that could prevent the submission.
Then you realize, you put it outside of the <form>:

<form>
  <!-- form fields -->
</form>
<button>Submit</button>
Enter fullscreen mode Exit fullscreen mode

Well, if the <button> tag is placed outside of <form> tag, it behaves pretty much like <button type="button">.
It's the same HTML syntax that acts differently whether it's inside of <form> tag or not.

Similary, this is also a disaster in the making:

<form action="/events">
  <form action="/events/5">
    <button>Submit</button>
  </form>

  <button>Submit</button>
</form>
Enter fullscreen mode Exit fullscreen mode

Similarly:

<label>
  <input type="checkbox" name="terms">
  I accept the <a href="/terms">Terms & Conditions</a>
</label>
Enter fullscreen mode Exit fullscreen mode

Or (these examples are not for faint hearted):

<a href="/events/5">
  <div>Best Ice-cream in town</div>
  <a href="/events/5/more-info">
    More info about Ice-cream party
  </a>

  <button>Submit</button>
</a>
Enter fullscreen mode Exit fullscreen mode

Let's talk some more about JavaScript

typeof [] === 'object' // WAT
typeof null === 'object' // WAT
typeof undefined === 'undefined' // WAT
Enter fullscreen mode Exit fullscreen mode
const add = (a = 1, b = 2) => {
  if (a && b) {
    return a + b
  } else {
    return 0
  }
}
add(undefined, undefined) === 3 // hmmm...ok
add(2, null) === 0 // WAT
add(3, undefined) === 5 // WAT
Enter fullscreen mode Exit fullscreen mode

I'll wrap up here. Please do share your experiences working on frontend. :) Thanks!

Featured ones: